Clear environment

rm(list = ls())

Load required packages

Packages have been installed with mamba into a specific, special conda environment set up to run RStudio sessions

library("DESeq2")
library("tidyverse")
library("EnhancedVolcano")
library("ggpubr")
library("scales")
library("grid")

Set up variables for paths

p_repo <- "~/projects-etc/2022_transcriptome-construction"
p_res <- "results/2022-1025"
p_txt <- "Alison/txt"

p_full <- paste(p_repo, p_res, p_txt, sep = "/")
dir.exists(p_full)

p_Alison <- gsub('(.*)/\\w+', '\\1', p_full)
dir.exists(p_Alison)

p_save <- paste(p_repo, p_res, sep = "/")

Read in count and metadata for mRNA

countData_Nascent <- read.delim(
    paste(p_full, "mRNA_Nascent_Nab3.txt", sep = "/"),
    header = TRUE
)
metadata_Nascent <- read.delim(
    paste(p_full, "deletionmeta.txt", sep = "/"),
    header = TRUE
)

Make DESEQDataSet Object

dds_n <- DESeq2::DESeqDataSetFromMatrix(
    countData=countData_Nascent,
    colData=metadata_Nascent, 
    design= ~ dex,
    tidy = TRUE
)
dds_n
# class: DESeqDataSet 
# dim: 6600 5 
# metadata(1): version
# assays(1): counts
# rownames(6600): Q0010 Q0017 ... YPR204C-A YPR204W
# rowData names(0):
# colnames(5): Q_6125_N Q_7718_N Q_6126_N Q_7716_N Q_7714_N
# colData names(2): id dex

Set size factors (from spike in)

BiocGenerics::sizeFactors(dds_n) <- c(1, 1.188, 1, 2.097, 1.662)

#QUESTION Is this where we want the estimated size factors to be input? #QUESTION Is the current means of calculating them appropriate for the DESeq2 model?

Run DESEQ Function

dds_n <- DESeq2::DESeq(dds_n)

Look at results table

res_n <- DESeq2::results(dds_n)
DESeq2::results(dds_n, tidy = TRUE) %>% head()

Summary of differential gene expression

summary(res_n)
# out of 6488 with nonzero total read count
# adjusted p-value < 0.1
# LFC > 0 (up)       : 2111, 33%
# LFC < 0 (down)     : 872, 13%
# outliers [1]       : 1, 0.015%
# low counts [2]     : 0, 0%
# (mean count < 0)
# [1] see 'cooksCutoff' argument of ?results
# [2] see 'independentFiltering' argument of ?results

Sort Summary List by adjusted p-value

res_n <- res_n[order(res_n$padj), ]
head(res_n)

Make volcano

EnhancedVolcano::EnhancedVolcano(
    res_n,
    lab = NA,
    x = 'log2FoldChange',
    y = 'pvalue'
)

Make volcano and save png

dir.exists(paste(p_save, "png", sep = "/")) ||
    dir.create(paste(p_save, "png", sep = "/"))

png <- EnhancedVolcano::EnhancedVolcano(
    res_n,
    lab = NA,
    x = 'log2FoldChange',
    y = 'padj',
    xlab = bquote(~Log[2]~ 'fold change'),
    title = 'Sense Nascent Transcription', 
    gridlines.major = FALSE,
    gridlines.minor = FALSE,
    pCutoff = 0.05,
    FCcutoff = 2
)

timestampedFilename <- paste0(
    paste(p_save, "png", sep = "/"), "/",
    "sense_differential_nascent_expression", ".",
    format(Sys.time(), format = "%F_%H%M%S"), ".png"
)
ggplot2::ggsave(timestampedFilename, plot = png)

Write DESeq2 to matrix

dir.exists(paste(p_save, "txt", sep = "/")) ||
    dir.create(paste(p_save, "txt", sep = "/"))

p_txt <- paste(p_save, "txt", sep = "/")
write.table(
    tibble::rownames_to_column(as.data.frame(res_n), "gene"),
    file = paste(p_txt, "nascent_mRNA_diff_res.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

write.table(
    tibble::rownames_to_column(
        as.data.frame(res_n[order(res_n$padj), ]), "gene"
    ),
    file = paste(p_txt, "nascent_mRNA_diff_res_ordered.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

#QUESTION I then go in excel and name the gene category “name” Why does R not name this column? I wish I knew

#ANSWER write.table is printing the row names which, by default, don’t have column names; the row names become the first column for all lines after the initial one; see the way I addressed this above

Read ordered DESeq2 matrix back in

#COMMENT There has gotta be a better way to do this

#ANSWER There is: see below

res1_n <- tibble::rownames_to_column(
    as.data.frame(res_n[order(res_n$padj), ]), "gene"
)

#filter results

res1Nab3_up <- dplyr::filter(res1_n, log2FoldChange > 2, padj < 0.05)
res1Nab3_down <- dplyr::filter(res1_n, log2FoldChange < -2, padj < 0.05)

#write filtered results for go terms

write.table(
    res1Nab3_up,
    file = paste(p_txt, "res1Nab3_up_SENSE.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

write.table(
    res1Nab3_down,
    file = paste(p_txt, "res1Nab3_down_SENSE.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

#filter results

res1Nab3_up_1p5 <- filter(res1_n, log2FoldChange > 1.5, padj < 0.05)
res1Nab3_down_1p5 <- filter(res1_n, log2FoldChange < -1.5, padj < 0.05)

#read in AS count and metadata

AS_countData_Nascent <- read.delim(
    paste(p_full, "AS_mRNA_Nascent_Nab3.txt", sep = "/"),
    header = TRUE
)
AS_metadata_Nascent <- read.delim(
    paste(p_full, "deletionmeta_AS.txt", sep = "/"),
    header = TRUE
)

Make DESEQDataSet Object AS

dds_n_as<- DESeq2::DESeqDataSetFromMatrix(
    countData = AS_countData_Nascent,
    colData = AS_metadata_Nascent, 
    design= ~ dex,
    tidy = TRUE
)
dds_n_as

#size factors #from spike in

BiocGenerics::sizeFactors(dds_n_as)  <-  c(1, 1.188, 1, 2.097, 1.662)

Run DESEQ Function

dds_n_as <- DESeq2::DESeq(dds_n_as)

Look at results table

res_n_as<- DESeq2::results(dds_n_as)
DESeq2::results(dds_n_as, tidy=TRUE) %>% head()

Summary of differential gene expression

summary(res_n_as)

##Sort Summary List by p-value

res_n_as <- res_n_as[order(res_n_as$padj), ]
head(res_n_as)

#make volcano plot - saves png

png <- EnhancedVolcano::EnhancedVolcano(
    res_n_as,
    lab = NA,
    x = 'log2FoldChange',
    y = 'padj',
    xlab = bquote(~Log[2]~ 'fold change'),
    title = 'Antisense Nascent Transcription', 
    gridlines.major = FALSE,
    gridlines.minor = FALSE,
    pCutoff = 0.05,
    FCcutoff = 2
)

timestampedFilename <- paste0(
    paste(p_save, "png", sep = "/"), "/",
    "AS_differential_nascent_expression", ".",
    format(Sys.time(), format = "%F_%H%M%S"), ".png"
)
ggplot2::ggsave(timestampedFilename, plot = png)

#write results file AS

write.table(
    tibble::rownames_to_column(as.data.frame(res_n_as), "gene"),
    file = paste(p_txt, "AS_Nascent_mRNA_diff_res_sf.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

write.table(
    tibble::rownames_to_column(
        as.data.frame(res_n_as[order(res_n_as$padj), ]), "gene"
    ),
    file = paste(p_txt, "AS_Nascent_mRNA_diff_res_sf_ordered.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)
res1_n_as <- tibble::rownames_to_column(
    as.data.frame(res_n_as[order(res_n_as$padj), ]), "gene"
)

#filter AS results

AS_res1Nab3_up <- dplyr::filter(res1_n_as, log2FoldChange > 2, padj < 0.05)
AS_res1Nab3_down <- dplyr::filter(res1_n_as, log2FoldChange < -2, padj < 0.05)

#write AS to file

write.table(
    AS_res1Nab3_up, 
    file = paste(p_txt, "AS_res1Nab3_up.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

write.table(
    AS_res1Nab3_down, 
    file = paste(p_txt, "AS_res1Nab3_down.txt", sep = "/"),
    sep = "\t",
    row.names = FALSE
)

#filter AS results different

AS_res1Nab3_up_1p5 <- dplyr::filter(res1_n_as, log2FoldChange > 1.5, padj < 0.05)
AS_res1Nab3_down_1p5 <- dplyr::filter(res1_n_as, log2FoldChange < -1.5, padj < 0.05)

#overlap between sense and AS by name

Nas_AS_up <- dplyr::inner_join(
    AS_res1Nab3_up,
    res1Nab3_up,
    by = "gene"
)
Nas_AS_down <- dplyr::inner_join(
    AS_res1Nab3_down,
    res1Nab3_down,
    by = "gene"
)
Nas_AS_down_up <- dplyr::inner_join(
    AS_res1Nab3_down,
    res1Nab3_up,
    by = "gene"
)
Nas_AS_up_down <- dplyr::inner_join(
    AS_res1Nab3_up,
    res1Nab3_down,
    by = "gene"
)

#overlap between sense and AS by name - different gates

Nas_1.5_AS_up <- dplyr::inner_join(
    AS_res1Nab3_up_1p5,
    res1Nab3_up_1p5,
    by = "gene"
)
Nas_1.5_AS_down <- dplyr::inner_join(
    AS_res1Nab3_down_1p5,
    res1Nab3_down_1p5,
    by = "gene"
)
Nas_1.5_AS_down_up <- dplyr::inner_join(
    AS_res1Nab3_down_1p5,
    res1Nab3_up_1p5,
    by = "gene"
)
Nas_1.5_AS_up_down <- dplyr::inner_join(
    AS_res1Nab3_up_1p5,
    res1Nab3_down_1p5,
    by = "gene"
)

#read in AS of Nab3 TPM - from replicate analysis rmd

AS_TPM <- read.delim(
    paste(p_full, "AS_TPM.txt", sep = "/"),
    header = TRUE
)

#calc average TPM


AS_TPM <- AS_TPM %>%
    dplyr::rowwise() %>%
    dplyr::mutate(
        Avg_single_Tag_AS_TPM = mean(c(Q_7718_N_AS, Q_7718_N_AS), na.rm = T)
    ) 
AS_TPM <- AS_TPM %>%
    dplyr::rowwise() %>%
    dplyr::mutate(
        Avg_parental_AS_TPM = mean(c(Q_6125_N_AS, Q_6126_N_AS), na.rm = T)
    )

#extract only relevent columns

AS_TPM_Clean <- AS_TPM %>%
    dplyr::select(c("name", "Avg_single_Tag_AS_TPM", "Avg_parental_AS_TPM"))

#  Change the "name" column to "gene" column
colnames(AS_TPM_Clean)[colnames(AS_TPM_Clean) == "name"] <- "gene"

#access quantiles

quantile(AS_TPM_Clean$Avg_single_Tag_AS_TPM) 
quantile(AS_TPM_Clean$Avg_parental_AS_TPM) 

#more fine grain

quantile(AS_TPM_Clean$Avg_single_Tag_AS_TPM, probs = c(0.8,0.85, .9, .95)) 
quantile(AS_TPM_Clean$Avg_parental_AS_TPM, probs = c(0.8,0.85, .9, .95)) 

#highest 20% of AS by absolute level

Cuttoff_TPM_AS <- dplyr::filter(AS_TPM_Clean, Avg_single_Tag_AS_TPM > 14)

#now were doing the intersection of AS of high level and differential expression

TPM_Nas_AS_up <- dplyr::inner_join(AS_res1Nab3_up, Cuttoff_TPM_AS, by = "gene")
nrow(TPM_Nas_AS_up)

#731 AS up

#overlap between TPM_Nas_AS_up and res1Nab3_down_1p5 (one way to gate functional AS)

TPM_AS_up_Sense_down <- dplyr::inner_join(
    TPM_Nas_AS_up,
    res1Nab3_down_1p5,
    by = "gene"
)
nrow(TPM_AS_up_Sense_down)
nrow(res1Nab3_down_1p5)

#overlap between TPM_Nas_AS_up and res1Nab3_down (different way to gate functional AS)

TPM_AS_up_Sense_down_2 <- dplyr::inner_join(
    TPM_Nas_AS_up,
    res1Nab3_down,
    by = "gene"
)
nrow(TPM_AS_up_Sense_down_2)
nrow(res1Nab3_down)

#rename AS table names so I can compare them with sense values - they will then have different names and labels

colnames(res1_n_as) <- c(
    "gene", "AS_baseMean", "AS_log2FoldChange", "AS_lfcSE",
    "AS_stat", "AS_pvalue", "AS_padj"
)

#one giant matrix of both sense and Antisense

Combinded_RES <- merge(res1_n, res1_n_as, by = "gene")

#graph logfoldchange of sense and Antisense #“pairwise.complete.obs” must be used to throw out incomplete values - I know some authors will change every zero to 1 to fix this

grob1 <- grid::grobTree(
    grid::textGrob(
        paste(
            "Pearson Correlation: ",
            round(cor(
                Combinded_RES$log2FoldChange,
                Combinded_RES$AS_log2FoldChange,
                use = "pairwise.complete.obs"),
            4)
        ),
        x = 0.5,
        y = 0.97,
        hjust = 0,
        gp = gpar(col = 'blue', fontsize = 11, fontface = "bold")
    )
)

ggplot2::ggplot(data = Combinded_RES) + 
    ggplot2::geom_vline(xintercept = 0, alpha = .5) +
    ggplot2::geom_hline(yintercept = 0, alpha = .5) +
    ggplot2::geom_point(
        data = Combinded_RES,
        mapping = aes(y = log2FoldChange, x = AS_log2FoldChange),
        alpha = 4/10,
        size = 1,
        color = 'black'
    ) +
    ggplot2::geom_smooth(
        aes(y = log2FoldChange, x = AS_log2FoldChange),
        method = lm,
        se = TRUE,
        color = 'forestgreen'
    ) +
    ggplot2::theme_bw() +
    ggplot2::annotation_custom(grob1) +
    ggplot2::geom_smooth(
        data = Combinded_RES,
        aes(y = log2FoldChange, x = AS_log2FoldChange),
        method = lm,
        se = TRUE,
        color = 'blue'
    )

#check colnames of TPM_Nas_AS_up

colnames(TPM_Nas_AS_up)

#rename AS table names so I can compare them with sense values - they will then have different names and labels

colnames(TPM_Nas_AS_up) <- c(
    "gene", "AS_baseMean", "AS_log2FoldChange", "AS_lfcSE", "AS_stat",
    "AS_pvalue", "AS_padj", "Avg_single_Tag_AS_TPM", "Avg_parental_AS_TPM"
)

#add sense expression info onto highest AS table so those points can be graphed seperately

High_up_AS <- merge(TPM_Nas_AS_up, res1_n, by = "gene")

#scatterplot now with high AS highlighted in red

grob2 <- grid::grobTree(
    grid::textGrob(
        paste(
            "Pearson Correlation Over Expressed AS: ",
            round(
                cor(
                    High_up_AS$log2FoldChange,
                    High_up_AS$AS_log2FoldChange,
                    use = "pairwise.complete.obs"),
                4
            )
        ),
        x= 0.3,
        y = 0.93,
        hjust = 0,
        gp = gpar(col = 'red', fontsize = 11, fontface = "bold")
    )
)

ggplot2::ggplot(data = Combinded_RES) + 
    ggplot2::geom_vline(xintercept = 0, alpha = .5) +
    ggplot2::geom_hline(yintercept = 0, alpha = .5) +
    ggplot2::geom_point(
        data = Combinded_RES,
        mapping = aes(y = log2FoldChange, x = AS_log2FoldChange),
        alpha = 4/10,
        size = 1,
        color = 'black'
    ) +
    ggplot2::geom_smooth(
        aes(y = log2FoldChange, x = AS_log2FoldChange),
        method = lm,
        se = TRUE,
        color = 'forestgreen'
    ) +
    ggplot2::theme_bw() +
    ggplot2::geom_point(
        data = High_up_AS, 
        aes(y = log2FoldChange,x=AS_log2FoldChange), 
        color = "red",
        size =1, 
        alpha = 4/10
    )+
    ggplot2::annotation_custom(grob1) +
    ggplot2::annotation_custom(grob2) +
    ggplot2::geom_smooth(
        data = Combinded_RES,
        aes(y = log2FoldChange, x = AS_log2FoldChange),
        method = lm,
        se = TRUE,
        color = 'blue'
    ) +
    ggplot2::geom_smooth(
        data = High_up_AS,
        aes(y = log2FoldChange, x = AS_log2FoldChange),
        method = lm,
        se = TRUE,
        color = "red"
    )

now it is time to do grouped analysis :)

#Make a new variable that’s the same thing (need this to remove genes, so no gene is asigned to more than one group)

#now we are binning genes by group of mRNA expression #group 1 up genes #group 5 down genes

#group 3 “neutral”

#remove group 1 genes from DeSeq2_Sense_Results

nrow(DeSeq2_Sense_Results) + nrow(grp1_DeSeq2_Sense_Results)
[1] 6600

#remove group 5 genes from DeSeq2_Sense_Results

nrow(grp1_DeSeq2_Sense_Results) + nrow(grp5_DeSeq2_Sense_Results)
[1] 808

#remove group 3 genes from DeSeq2_Sense_Results

nrow(grp3_DeSeq2_Sense_Results)
[1] 4418

#sanity check count rows

nrow(grp5_DeSeq2_Sense_Results)
[1] 72

#now from not group 1,3,5 - split into group 2 and 4

#sanity check count rows

nrow(grp1_DeSeq2_Sense_Results) +
nrow(grp5_DeSeq2_Sense_Results) +
nrow(grp3_DeSeq2_Sense_Results) +
nrow(grp2_DeSeq2_Sense_Results) +
nrow(grp4_DeSeq2_Sense_Results)
[1] 6488

#sanity check count rows

nrow(grp1_DeSeq2_Sense_Results) + nrow(grp5_DeSeq2_Sense_Results)
[1] 808

#sanity check count rows #only thing left in “DeSeq2_Sense_Results” is NA results

nrow(DeSeq2_Sense_Results)
[1] 112

#now we have groups by sense expression change #now make table to integrate AS expression info

#what happens next is how i make violin plots. #I figured this out like a year ago and have copy pasted this code a bunch. #this is the bins

#now the little seperate bins are glued together

#now we we make a violin plot

#now we we make a violin plot with p values

#now were going to do the same thing #the bins stay the same #but in the bins were are putting AS expression level

colnames(TPM_group1)
 [1] "gene"                  "baseMean"              "log2FoldChange"        "lfcSE"                 "stat"                  "pvalue"               
 [7] "padj"                  "Q_6125_N_AS"           "Q_7718_N_AS"           "Q_6126_N_AS"           "Q_7716_N_AS"           "length_kb"            
[13] "ratio_6125"            "ratio_6126"            "Avg_single_Tag_AS_TPM" "Avg_parental_AS_TPM"  

#making data frames to put into violin plot

#glueing the data frames into one

#make violin plot

#make violin plot but now with p values

#now I am gating by fold change >2 instead of 4

#comparing between fold change >2 instead of 4

nrow(ONE_TPM_Nas_AS_up)
[1] 878

#New Sense filters

#new functional RNA catagory

nrow(ONE_UpAS_DownMRNA)
[1] 187

#write names only to file #thanks for writing this Kris

close(fileConn)
Error in UseMethod("close") : 
  no applicable method for 'close' applied to an object of class "character"

#calc overlaps

nrow(ONE_res1Nab3_up)
[1] 1496

#HERE ##now I am going to compare to 5781 and 2 WT Q and G1 #so I gotta read that data in

#filtered by expression

#calc what high AS is

quantile(WT_TPM$Avg_Q_IP_ANTISense, probs = c(0.5, 0.75, 0.8,0.85, 0.9, 0.95)) 
      50%       75%       80%       85%       90%       95% 
 3.369446 10.541939 14.414169 21.709871 36.698259 79.249805 

#once again I am gating at 80%

#check colnames

colnames(WT_high_level_AS)
 [1] "ensgene"             "s5781_G1_IP"         "s5781_Q_IP"          "s5782_G1_IP"         "s5782_Q_IP"          "s5781_G1_IP_AS"      "s5781_Q_IP_AS"      
 [8] "s5782_G1_IP_AS"      "s5782_Q_IP_AS"       "length_kb"           "Avg_Q_IP_Sense"      "Avg_G1_IP_Sense"     "Avg_Q_IP_ANTISense"  "Avg_G1_IP_ANTISense"

#merge high level and overexpressed

#now compare WT to Nab3 experiment

nrow(High_up_AS)
[1] 731

#of the 180 above - how many are functional?

nrow(AS_tested)
[1] 180

#making a list of gene names from Nab3 data so I can highlight those genes in WT data

nrow(ONE_TPM_Nas_AS_up_list)
[1] 878

#all genes in WT - AS tpm and differential expression

#graph it and it is a blob

#map Nab3 genes to WT data

#graph it and it is 2 blobs!! :)

#graph it again

#all on one. busy, very hard to look at.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKLS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIENsZWFyIGVudmlyb25tZW50CmBgYHtyfQpybShsaXN0ID0gbHMoKSkKYGBgCgojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMKIyMgUGFja2FnZXMgaGF2ZSBiZWVuIGluc3RhbGxlZCB3aXRoIG1hbWJhIGludG8gYSBzcGVjaWZpYywgc3BlY2lhbCBjb25kYSBlbnZpcm9ubWVudCBzZXQgdXAgdG8gcnVuIFJTdHVkaW8gc2Vzc2lvbnMKYGBge3J9CmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoInRpZHl2ZXJzZSIpCmxpYnJhcnkoIkVuaGFuY2VkVm9sY2FubyIpCmxpYnJhcnkoImdncHViciIpCmxpYnJhcnkoInNjYWxlcyIpCmxpYnJhcnkoImdyaWQiKQpgYGAKCiMgU2V0IHVwIHZhcmlhYmxlcyBmb3IgcGF0aHMKYGBge3J9CnBfcmVwbyA8LSAifi9wcm9qZWN0cy1ldGMvMjAyMl90cmFuc2NyaXB0b21lLWNvbnN0cnVjdGlvbiIKcF9yZXMgPC0gInJlc3VsdHMvMjAyMi0xMDI1IgpwX3R4dCA8LSAiQWxpc29uL3R4dCIKCnBfZnVsbCA8LSBwYXN0ZShwX3JlcG8sIHBfcmVzLCBwX3R4dCwgc2VwID0gIi8iKQpkaXIuZXhpc3RzKHBfZnVsbCkKCnBfQWxpc29uIDwtIGdzdWIoJyguKikvXFx3KycsICdcXDEnLCBwX2Z1bGwpCmRpci5leGlzdHMocF9BbGlzb24pCgpwX3NhdmUgPC0gcGFzdGUocF9yZXBvLCBwX3Jlcywgc2VwID0gIi8iKQpgYGAKCiMgUmVhZCBpbiBjb3VudCBhbmQgbWV0YWRhdGEgZm9yIG1STkEKYGBge3J9CmNvdW50RGF0YV9OYXNjZW50IDwtIHJlYWQuZGVsaW0oCiAgICBwYXN0ZShwX2Z1bGwsICJtUk5BX05hc2NlbnRfTmFiMy50eHQiLCBzZXAgPSAiLyIpLAogICAgaGVhZGVyID0gVFJVRQopCm1ldGFkYXRhX05hc2NlbnQgPC0gcmVhZC5kZWxpbSgKICAgIHBhc3RlKHBfZnVsbCwgImRlbGV0aW9ubWV0YS50eHQiLCBzZXAgPSAiLyIpLAogICAgaGVhZGVyID0gVFJVRQopCmBgYAoKCiMjIE1ha2UgREVTRVFEYXRhU2V0IE9iamVjdApgYGB7cn0KZGRzX24gPC0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KAogICAgY291bnREYXRhPWNvdW50RGF0YV9OYXNjZW50LAogICAgY29sRGF0YT1tZXRhZGF0YV9OYXNjZW50LCAKICAgIGRlc2lnbj0gfiBkZXgsCiAgICB0aWR5ID0gVFJVRQopCmRkc19uCiMgY2xhc3M6IERFU2VxRGF0YVNldCAKIyBkaW06IDY2MDAgNSAKIyBtZXRhZGF0YSgxKTogdmVyc2lvbgojIGFzc2F5cygxKTogY291bnRzCiMgcm93bmFtZXMoNjYwMCk6IFEwMDEwIFEwMDE3IC4uLiBZUFIyMDRDLUEgWVBSMjA0VwojIHJvd0RhdGEgbmFtZXMoMCk6CiMgY29sbmFtZXMoNSk6IFFfNjEyNV9OIFFfNzcxOF9OIFFfNjEyNl9OIFFfNzcxNl9OIFFfNzcxNF9OCiMgY29sRGF0YSBuYW1lcygyKTogaWQgZGV4CmBgYAoKIyMgU2V0IHNpemUgZmFjdG9ycyAoZnJvbSBzcGlrZSBpbikKYGBge3J9CkJpb2NHZW5lcmljczo6c2l6ZUZhY3RvcnMoZGRzX24pIDwtIGMoMSwgMS4xODgsIDEsIDIuMDk3LCAxLjY2MikKYGBgCgpgI1FVRVNUSU9OYCBJcyB0aGlzIHdoZXJlIHdlIHdhbnQgdGhlIGVzdGltYXRlZCBzaXplIGZhY3RvcnMgdG8gYmUgaW5wdXQ/CmAjUVVFU1RJT05gIElzIHRoZSBjdXJyZW50IG1lYW5zIG9mIGNhbGN1bGF0aW5nIHRoZW0gYXBwcm9wcmlhdGUgZm9yIHRoZSBERVNlcTIgbW9kZWw/CgojIyBSdW4gREVTRVEgRnVuY3Rpb24KYGBge3J9CmRkc19uIDwtIERFU2VxMjo6REVTZXEoZGRzX24pCmBgYAoKIyMgTG9vayBhdCByZXN1bHRzIHRhYmxlCmBgYHtyfQpyZXNfbiA8LSBERVNlcTI6OnJlc3VsdHMoZGRzX24pCkRFU2VxMjo6cmVzdWx0cyhkZHNfbiwgdGlkeSA9IFRSVUUpICU+JSBoZWFkKCkKYGBgCgoKIyMgU3VtbWFyeSBvZiBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uCmBgYHtyfQpzdW1tYXJ5KHJlc19uKQojIG91dCBvZiA2NDg4IHdpdGggbm9uemVybyB0b3RhbCByZWFkIGNvdW50CiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQojIExGQyA+IDAgKHVwKSAgICAgICA6IDIxMTEsIDMzJQojIExGQyA8IDAgKGRvd24pICAgICA6IDg3MiwgMTMlCiMgb3V0bGllcnMgWzFdICAgICAgIDogMSwgMC4wMTUlCiMgbG93IGNvdW50cyBbMl0gICAgIDogMCwgMCUKIyAobWVhbiBjb3VudCA8IDApCiMgWzFdIHNlZSAnY29va3NDdXRvZmYnIGFyZ3VtZW50IG9mID9yZXN1bHRzCiMgWzJdIHNlZSAnaW5kZXBlbmRlbnRGaWx0ZXJpbmcnIGFyZ3VtZW50IG9mID9yZXN1bHRzCmBgYAoKCiMjIyBTb3J0IFN1bW1hcnkgTGlzdCBieSBhZGp1c3RlZCBwLXZhbHVlCmBgYHtyfQpyZXNfbiA8LSByZXNfbltvcmRlcihyZXNfbiRwYWRqKSwgXQpoZWFkKHJlc19uKQpgYGAKCiMjIyBNYWtlIHZvbGNhbm8KYGBge3J9CkVuaGFuY2VkVm9sY2Fubzo6RW5oYW5jZWRWb2xjYW5vKAogICAgcmVzX24sCiAgICBsYWIgPSBOQSwKICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLAogICAgeSA9ICdwdmFsdWUnCikKYGBgCgojIyMgTWFrZSB2b2xjYW5vIGFuZCBzYXZlIHBuZwpgYGB7cn0KZGlyLmV4aXN0cyhwYXN0ZShwX3NhdmUsICJwbmciLCBzZXAgPSAiLyIpKSB8fAogICAgZGlyLmNyZWF0ZShwYXN0ZShwX3NhdmUsICJwbmciLCBzZXAgPSAiLyIpKQoKcG5nIDwtIEVuaGFuY2VkVm9sY2Fubzo6RW5oYW5jZWRWb2xjYW5vKAogICAgcmVzX24sCiAgICBsYWIgPSBOQSwKICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLAogICAgeSA9ICdwYWRqJywKICAgIHhsYWIgPSBicXVvdGUofkxvZ1syXX4gJ2ZvbGQgY2hhbmdlJyksCiAgICB0aXRsZSA9ICdTZW5zZSBOYXNjZW50IFRyYW5zY3JpcHRpb24nLCAKICAgIGdyaWRsaW5lcy5tYWpvciA9IEZBTFNFLAogICAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgICBwQ3V0b2ZmID0gMC4wNSwKICAgIEZDY3V0b2ZmID0gMgopCgp0aW1lc3RhbXBlZEZpbGVuYW1lIDwtIHBhc3RlMCgKICAgIHBhc3RlKHBfc2F2ZSwgInBuZyIsIHNlcCA9ICIvIiksICIvIiwKICAgICJzZW5zZV9kaWZmZXJlbnRpYWxfbmFzY2VudF9leHByZXNzaW9uIiwgIi4iLAogICAgZm9ybWF0KFN5cy50aW1lKCksIGZvcm1hdCA9ICIlRl8lSCVNJVMiKSwgIi5wbmciCikKZ2dwbG90Mjo6Z2dzYXZlKHRpbWVzdGFtcGVkRmlsZW5hbWUsIHBsb3QgPSBwbmcpCmBgYAoKIyMjIFdyaXRlIERFU2VxMiB0byBtYXRyaXgKYGBge3J9CmRpci5leGlzdHMocGFzdGUocF9zYXZlLCAidHh0Iiwgc2VwID0gIi8iKSkgfHwKICAgIGRpci5jcmVhdGUocGFzdGUocF9zYXZlLCAidHh0Iiwgc2VwID0gIi8iKSkKCnBfdHh0IDwtIHBhc3RlKHBfc2F2ZSwgInR4dCIsIHNlcCA9ICIvIikKd3JpdGUudGFibGUoCiAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbihhcy5kYXRhLmZyYW1lKHJlc19uKSwgImdlbmUiKSwKICAgIGZpbGUgPSBwYXN0ZShwX3R4dCwgIm5hc2NlbnRfbVJOQV9kaWZmX3Jlcy50eHQiLCBzZXAgPSAiLyIpLAogICAgc2VwID0gIlx0IiwKICAgIHJvdy5uYW1lcyA9IEZBTFNFCikKCndyaXRlLnRhYmxlKAogICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oCiAgICAgICAgYXMuZGF0YS5mcmFtZShyZXNfbltvcmRlcihyZXNfbiRwYWRqKSwgXSksICJnZW5lIgogICAgKSwKICAgIGZpbGUgPSBwYXN0ZShwX3R4dCwgIm5hc2NlbnRfbVJOQV9kaWZmX3Jlc19vcmRlcmVkLnR4dCIsIHNlcCA9ICIvIiksCiAgICBzZXAgPSAiXHQiLAogICAgcm93Lm5hbWVzID0gRkFMU0UKKQpgYGAKYCNRVUVTVElPTmAgSSB0aGVuIGdvIGluIGV4Y2VsIGFuZCBuYW1lIHRoZSBnZW5lIGNhdGVnb3J5ICJuYW1lIiBXaHkgZG9lcyBSIG5vdCBuYW1lIHRoaXMgY29sdW1uPyBJIHdpc2ggSSBrbmV3CgpgI0FOU1dFUmAgYHdyaXRlLnRhYmxlYCBpcyBwcmludGluZyB0aGUgcm93IG5hbWVzIHdoaWNoLCBieSBkZWZhdWx0LCBkb24ndCBoYXZlIGNvbHVtbiBuYW1lczsgdGhlIHJvdyBuYW1lcyBiZWNvbWUgdGhlIGZpcnN0IGNvbHVtbiBmb3IgYWxsIGxpbmVzIGFmdGVyIHRoZSBpbml0aWFsIG9uZTsgc2VlIHRoZSB3YXkgSSBhZGRyZXNzZWQgdGhpcyBhYm92ZQoKIyMjIFJlYWQgb3JkZXJlZCBERVNlcTIgbWF0cml4IGJhY2sgaW4KYCNDT01NRU5UYCBUaGVyZSBoYXMgZ290dGEgYmUgYSBiZXR0ZXIgd2F5IHRvIGRvIHRoaXMKCmAjQU5TV0VSYCBUaGVyZSBpczogc2VlIGJlbG93CmBgYHtyfQpyZXMxX24gPC0gdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oCiAgICBhcy5kYXRhLmZyYW1lKHJlc19uW29yZGVyKHJlc19uJHBhZGopLCBdKSwgImdlbmUiCikKYGBgCgojZmlsdGVyIHJlc3VsdHMKYGBge3J9CnJlczFOYWIzX3VwIDwtIGRwbHlyOjpmaWx0ZXIocmVzMV9uLCBsb2cyRm9sZENoYW5nZSA+IDIsIHBhZGogPCAwLjA1KQpyZXMxTmFiM19kb3duIDwtIGRwbHlyOjpmaWx0ZXIocmVzMV9uLCBsb2cyRm9sZENoYW5nZSA8IC0yLCBwYWRqIDwgMC4wNSkKYGBgCgojd3JpdGUgZmlsdGVyZWQgcmVzdWx0cyBmb3IgZ28gdGVybXMKYGBge3J9CndyaXRlLnRhYmxlKAogICAgcmVzMU5hYjNfdXAsCiAgICBmaWxlID0gcGFzdGUocF90eHQsICJyZXMxTmFiM191cF9TRU5TRS50eHQiLCBzZXAgPSAiLyIpLAogICAgc2VwID0gIlx0IiwKICAgIHJvdy5uYW1lcyA9IEZBTFNFCikKCndyaXRlLnRhYmxlKAogICAgcmVzMU5hYjNfZG93biwKICAgIGZpbGUgPSBwYXN0ZShwX3R4dCwgInJlczFOYWIzX2Rvd25fU0VOU0UudHh0Iiwgc2VwID0gIi8iKSwKICAgIHNlcCA9ICJcdCIsCiAgICByb3cubmFtZXMgPSBGQUxTRQopCmBgYAoKI2ZpbHRlciByZXN1bHRzCmBgYHtyfQpyZXMxTmFiM191cF8xcDUgPC0gZmlsdGVyKHJlczFfbiwgbG9nMkZvbGRDaGFuZ2UgPiAxLjUsIHBhZGogPCAwLjA1KQpyZXMxTmFiM19kb3duXzFwNSA8LSBmaWx0ZXIocmVzMV9uLCBsb2cyRm9sZENoYW5nZSA8IC0xLjUsIHBhZGogPCAwLjA1KQpgYGAKCgojcmVhZCBpbiBBUyBjb3VudCBhbmQgbWV0YWRhdGEKYGBge3J9CkFTX2NvdW50RGF0YV9OYXNjZW50IDwtIHJlYWQuZGVsaW0oCiAgICBwYXN0ZShwX2Z1bGwsICJBU19tUk5BX05hc2NlbnRfTmFiMy50eHQiLCBzZXAgPSAiLyIpLAogICAgaGVhZGVyID0gVFJVRQopCkFTX21ldGFkYXRhX05hc2NlbnQgPC0gcmVhZC5kZWxpbSgKICAgIHBhc3RlKHBfZnVsbCwgImRlbGV0aW9ubWV0YV9BUy50eHQiLCBzZXAgPSAiLyIpLAogICAgaGVhZGVyID0gVFJVRQopCmBgYAoKCiMjIE1ha2UgREVTRVFEYXRhU2V0IE9iamVjdCBBUwpgYGB7cn0KZGRzX25fYXM8LSBERVNlcTI6OkRFU2VxRGF0YVNldEZyb21NYXRyaXgoCiAgICBjb3VudERhdGEgPSBBU19jb3VudERhdGFfTmFzY2VudCwKICAgIGNvbERhdGEgPSBBU19tZXRhZGF0YV9OYXNjZW50LCAKICAgIGRlc2lnbj0gfiBkZXgsCiAgICB0aWR5ID0gVFJVRQopCmRkc19uX2FzCmBgYAoKI3NpemUgZmFjdG9ycwojZnJvbSBzcGlrZSBpbgpgYGB7cn0KQmlvY0dlbmVyaWNzOjpzaXplRmFjdG9ycyhkZHNfbl9hcykgIDwtICBjKDEsIDEuMTg4LCAxLCAyLjA5NywgMS42NjIpCmBgYAoKCiMjIFJ1biBERVNFUSBGdW5jdGlvbgpgYGB7cn0KZGRzX25fYXMgPC0gREVTZXEyOjpERVNlcShkZHNfbl9hcykKYGBgCgoKIyMgTG9vayBhdCByZXN1bHRzIHRhYmxlCmBgYHtyfQpyZXNfbl9hczwtIERFU2VxMjo6cmVzdWx0cyhkZHNfbl9hcykKREVTZXEyOjpyZXN1bHRzKGRkc19uX2FzLCB0aWR5PVRSVUUpICU+JSBoZWFkKCkKYGBgCgoKIyMgU3VtbWFyeSBvZiBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uCmBgYHtyfQpzdW1tYXJ5KHJlc19uX2FzKQpgYGAKCgojI1NvcnQgU3VtbWFyeSBMaXN0IGJ5IHAtdmFsdWUKYGBge3J9CnJlc19uX2FzIDwtIHJlc19uX2FzW29yZGVyKHJlc19uX2FzJHBhZGopLCBdCmhlYWQocmVzX25fYXMpCmBgYAoKI21ha2Ugdm9sY2FubyBwbG90IC0gc2F2ZXMgcG5nIApgYGB7cn0KcG5nIDwtIEVuaGFuY2VkVm9sY2Fubzo6RW5oYW5jZWRWb2xjYW5vKAogICAgcmVzX25fYXMsCiAgICBsYWIgPSBOQSwKICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLAogICAgeSA9ICdwYWRqJywKICAgIHhsYWIgPSBicXVvdGUofkxvZ1syXX4gJ2ZvbGQgY2hhbmdlJyksCiAgICB0aXRsZSA9ICdBbnRpc2Vuc2UgTmFzY2VudCBUcmFuc2NyaXB0aW9uJywgCiAgICBncmlkbGluZXMubWFqb3IgPSBGQUxTRSwKICAgIGdyaWRsaW5lcy5taW5vciA9IEZBTFNFLAogICAgcEN1dG9mZiA9IDAuMDUsCiAgICBGQ2N1dG9mZiA9IDIKKQoKdGltZXN0YW1wZWRGaWxlbmFtZSA8LSBwYXN0ZTAoCiAgICBwYXN0ZShwX3NhdmUsICJwbmciLCBzZXAgPSAiLyIpLCAiLyIsCiAgICAiQVNfZGlmZmVyZW50aWFsX25hc2NlbnRfZXhwcmVzc2lvbiIsICIuIiwKICAgIGZvcm1hdChTeXMudGltZSgpLCBmb3JtYXQgPSAiJUZfJUglTSVTIiksICIucG5nIgopCmdncGxvdDI6Omdnc2F2ZSh0aW1lc3RhbXBlZEZpbGVuYW1lLCBwbG90ID0gcG5nKQpgYGAKCiN3cml0ZSByZXN1bHRzIGZpbGUgQVMKYGBge3J9CndyaXRlLnRhYmxlKAogICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oYXMuZGF0YS5mcmFtZShyZXNfbl9hcyksICJnZW5lIiksCiAgICBmaWxlID0gcGFzdGUocF90eHQsICJBU19OYXNjZW50X21STkFfZGlmZl9yZXNfc2YudHh0Iiwgc2VwID0gIi8iKSwKICAgIHNlcCA9ICJcdCIsCiAgICByb3cubmFtZXMgPSBGQUxTRQopCgp3cml0ZS50YWJsZSgKICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKAogICAgICAgIGFzLmRhdGEuZnJhbWUocmVzX25fYXNbb3JkZXIocmVzX25fYXMkcGFkaiksIF0pLCAiZ2VuZSIKICAgICksCiAgICBmaWxlID0gcGFzdGUocF90eHQsICJBU19OYXNjZW50X21STkFfZGlmZl9yZXNfc2Zfb3JkZXJlZC50eHQiLCBzZXAgPSAiLyIpLAogICAgc2VwID0gIlx0IiwKICAgIHJvdy5uYW1lcyA9IEZBTFNFCikKYGBgCgpgYGB7cn0KcmVzMV9uX2FzIDwtIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKAogICAgYXMuZGF0YS5mcmFtZShyZXNfbl9hc1tvcmRlcihyZXNfbl9hcyRwYWRqKSwgXSksICJnZW5lIgopCmBgYAoKI2ZpbHRlciBBUyByZXN1bHRzIApgYGB7cn0KQVNfcmVzMU5hYjNfdXAgPC0gZHBseXI6OmZpbHRlcihyZXMxX25fYXMsIGxvZzJGb2xkQ2hhbmdlID4gMiwgcGFkaiA8IDAuMDUpCkFTX3JlczFOYWIzX2Rvd24gPC0gZHBseXI6OmZpbHRlcihyZXMxX25fYXMsIGxvZzJGb2xkQ2hhbmdlIDwgLTIsIHBhZGogPCAwLjA1KQpgYGAKCiN3cml0ZSBBUyB0byBmaWxlIApgYGB7cn0Kd3JpdGUudGFibGUoCiAgICBBU19yZXMxTmFiM191cCwgCiAgICBmaWxlID0gcGFzdGUocF90eHQsICJBU19yZXMxTmFiM191cC50eHQiLCBzZXAgPSAiLyIpLAogICAgc2VwID0gIlx0IiwKICAgIHJvdy5uYW1lcyA9IEZBTFNFCikKCndyaXRlLnRhYmxlKAogICAgQVNfcmVzMU5hYjNfZG93biwgCiAgICBmaWxlID0gcGFzdGUocF90eHQsICJBU19yZXMxTmFiM19kb3duLnR4dCIsIHNlcCA9ICIvIiksCiAgICBzZXAgPSAiXHQiLAogICAgcm93Lm5hbWVzID0gRkFMU0UKKQpgYGAKCgojZmlsdGVyIEFTIHJlc3VsdHMgZGlmZmVyZW50IApgYGB7cn0KQVNfcmVzMU5hYjNfdXBfMXA1IDwtIGRwbHlyOjpmaWx0ZXIocmVzMV9uX2FzLCBsb2cyRm9sZENoYW5nZSA+IDEuNSwgcGFkaiA8IDAuMDUpCkFTX3JlczFOYWIzX2Rvd25fMXA1IDwtIGRwbHlyOjpmaWx0ZXIocmVzMV9uX2FzLCBsb2cyRm9sZENoYW5nZSA8IC0xLjUsIHBhZGogPCAwLjA1KQpgYGAKCgojb3ZlcmxhcCBiZXR3ZWVuIHNlbnNlIGFuZCBBUyBieSBuYW1lIApgYGB7cn0KTmFzX0FTX3VwIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgQVNfcmVzMU5hYjNfdXAsCiAgICByZXMxTmFiM191cCwKICAgIGJ5ID0gImdlbmUiCikKTmFzX0FTX2Rvd24gPC0gZHBseXI6OmlubmVyX2pvaW4oCiAgICBBU19yZXMxTmFiM19kb3duLAogICAgcmVzMU5hYjNfZG93biwKICAgIGJ5ID0gImdlbmUiCikKTmFzX0FTX2Rvd25fdXAgPC0gZHBseXI6OmlubmVyX2pvaW4oCiAgICBBU19yZXMxTmFiM19kb3duLAogICAgcmVzMU5hYjNfdXAsCiAgICBieSA9ICJnZW5lIgopCk5hc19BU191cF9kb3duIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgQVNfcmVzMU5hYjNfdXAsCiAgICByZXMxTmFiM19kb3duLAogICAgYnkgPSAiZ2VuZSIKKQpgYGAKCiNvdmVybGFwIGJldHdlZW4gc2Vuc2UgYW5kIEFTIGJ5IG5hbWUgLSBkaWZmZXJlbnQgZ2F0ZXMgCmBgYHtyfQpOYXNfMS41X0FTX3VwIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgQVNfcmVzMU5hYjNfdXBfMXA1LAogICAgcmVzMU5hYjNfdXBfMXA1LAogICAgYnkgPSAiZ2VuZSIKKQpOYXNfMS41X0FTX2Rvd24gPC0gZHBseXI6OmlubmVyX2pvaW4oCiAgICBBU19yZXMxTmFiM19kb3duXzFwNSwKICAgIHJlczFOYWIzX2Rvd25fMXA1LAogICAgYnkgPSAiZ2VuZSIKKQpOYXNfMS41X0FTX2Rvd25fdXAgPC0gZHBseXI6OmlubmVyX2pvaW4oCiAgICBBU19yZXMxTmFiM19kb3duXzFwNSwKICAgIHJlczFOYWIzX3VwXzFwNSwKICAgIGJ5ID0gImdlbmUiCikKTmFzXzEuNV9BU191cF9kb3duIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgQVNfcmVzMU5hYjNfdXBfMXA1LAogICAgcmVzMU5hYjNfZG93bl8xcDUsCiAgICBieSA9ICJnZW5lIgopCmBgYAoKI3JlYWQgaW4gQVMgb2YgTmFiMyBUUE0gLSBmcm9tIHJlcGxpY2F0ZSBhbmFseXNpcyBybWQgCmBgYHtyfQpBU19UUE0gPC0gcmVhZC5kZWxpbSgKICAgIHBhc3RlKHBfZnVsbCwgIkFTX1RQTS50eHQiLCBzZXAgPSAiLyIpLAogICAgaGVhZGVyID0gVFJVRQopCmBgYAoKI2NhbGMgYXZlcmFnZSBUUE0gCmBgYHtyfQoKQVNfVFBNIDwtIEFTX1RQTSAlPiUKICAgIGRwbHlyOjpyb3d3aXNlKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgIEF2Z19zaW5nbGVfVGFnX0FTX1RQTSA9IG1lYW4oYyhRXzc3MThfTl9BUywgUV83NzE4X05fQVMpLCBuYS5ybSA9IFQpCiAgICApIApBU19UUE0gPC0gQVNfVFBNICU+JQogICAgZHBseXI6OnJvd3dpc2UoKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgQXZnX3BhcmVudGFsX0FTX1RQTSA9IG1lYW4oYyhRXzYxMjVfTl9BUywgUV82MTI2X05fQVMpLCBuYS5ybSA9IFQpCiAgICApCgpgYGAKCiNleHRyYWN0IG9ubHkgcmVsZXZlbnQgY29sdW1ucyAKYGBge3J9CkFTX1RQTV9DbGVhbiA8LSBBU19UUE0gJT4lCiAgICBkcGx5cjo6c2VsZWN0KGMoIm5hbWUiLCAiQXZnX3NpbmdsZV9UYWdfQVNfVFBNIiwgIkF2Z19wYXJlbnRhbF9BU19UUE0iKSkKCiMgIENoYW5nZSB0aGUgIm5hbWUiIGNvbHVtbiB0byAiZ2VuZSIgY29sdW1uCmNvbG5hbWVzKEFTX1RQTV9DbGVhbilbY29sbmFtZXMoQVNfVFBNX0NsZWFuKSA9PSAibmFtZSJdIDwtICJnZW5lIgpgYGAKCiNhY2Nlc3MgcXVhbnRpbGVzIApgYGB7cn0KcXVhbnRpbGUoQVNfVFBNX0NsZWFuJEF2Z19zaW5nbGVfVGFnX0FTX1RQTSkgCnF1YW50aWxlKEFTX1RQTV9DbGVhbiRBdmdfcGFyZW50YWxfQVNfVFBNKSAKYGBgCgojbW9yZSBmaW5lIGdyYWluIApgYGB7cn0KcXVhbnRpbGUoQVNfVFBNX0NsZWFuJEF2Z19zaW5nbGVfVGFnX0FTX1RQTSwgcHJvYnMgPSBjKDAuOCwwLjg1LCAuOSwgLjk1KSkgCnF1YW50aWxlKEFTX1RQTV9DbGVhbiRBdmdfcGFyZW50YWxfQVNfVFBNLCBwcm9icyA9IGMoMC44LDAuODUsIC45LCAuOTUpKSAKYGBgCgojaGlnaGVzdCAyMCUgb2YgQVMgYnkgYWJzb2x1dGUgbGV2ZWwgCmBgYHtyfQpDdXR0b2ZmX1RQTV9BUyA8LSBkcGx5cjo6ZmlsdGVyKEFTX1RQTV9DbGVhbiwgQXZnX3NpbmdsZV9UYWdfQVNfVFBNID4gMTQpCmBgYAoKI25vdyB3ZXJlIGRvaW5nIHRoZSBpbnRlcnNlY3Rpb24gb2YgQVMgb2YgaGlnaCBsZXZlbCBhbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gCmBgYHtyfQpUUE1fTmFzX0FTX3VwIDwtIGRwbHlyOjppbm5lcl9qb2luKEFTX3JlczFOYWIzX3VwLCBDdXR0b2ZmX1RQTV9BUywgYnkgPSAiZ2VuZSIpCm5yb3coVFBNX05hc19BU191cCkKYGBgCiM3MzEgQVMgdXAgCgojb3ZlcmxhcCBiZXR3ZWVuIFRQTV9OYXNfQVNfdXAgYW5kIHJlczFOYWIzX2Rvd25fMXA1IChvbmUgd2F5IHRvIGdhdGUgZnVuY3Rpb25hbCBBUykKYGBge3J9ClRQTV9BU191cF9TZW5zZV9kb3duIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgVFBNX05hc19BU191cCwKICAgIHJlczFOYWIzX2Rvd25fMXA1LAogICAgYnkgPSAiZ2VuZSIKKQpucm93KFRQTV9BU191cF9TZW5zZV9kb3duKQpucm93KHJlczFOYWIzX2Rvd25fMXA1KQpgYGAKCiNvdmVybGFwIGJldHdlZW4gVFBNX05hc19BU191cCBhbmQgcmVzMU5hYjNfZG93biAoZGlmZmVyZW50IHdheSB0byBnYXRlIGZ1bmN0aW9uYWwgQVMpCmBgYHtyfQpUUE1fQVNfdXBfU2Vuc2VfZG93bl8yIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgVFBNX05hc19BU191cCwKICAgIHJlczFOYWIzX2Rvd24sCiAgICBieSA9ICJnZW5lIgopCm5yb3coVFBNX0FTX3VwX1NlbnNlX2Rvd25fMikKbnJvdyhyZXMxTmFiM19kb3duKQpgYGAKCiNyZW5hbWUgQVMgdGFibGUgbmFtZXMgc28gSSBjYW4gY29tcGFyZSB0aGVtIHdpdGggc2Vuc2UgdmFsdWVzIC0gdGhleSB3aWxsIHRoZW4gaGF2ZSBkaWZmZXJlbnQgbmFtZXMgYW5kIGxhYmVscyAKYGBge3J9CmNvbG5hbWVzKHJlczFfbl9hcykgPC0gYygKICAgICJnZW5lIiwgIkFTX2Jhc2VNZWFuIiwgIkFTX2xvZzJGb2xkQ2hhbmdlIiwgIkFTX2xmY1NFIiwKICAgICJBU19zdGF0IiwgIkFTX3B2YWx1ZSIsICJBU19wYWRqIgopCmBgYAoKI29uZSBnaWFudCBtYXRyaXggb2YgYm90aCBzZW5zZSBhbmQgQW50aXNlbnNlIApgYGB7cn0KQ29tYmluZGVkX1JFUyA8LSBtZXJnZShyZXMxX24sIHJlczFfbl9hcywgYnkgPSAiZ2VuZSIpCmBgYAoKI2dyYXBoIGxvZ2ZvbGRjaGFuZ2Ugb2Ygc2Vuc2UgYW5kIEFudGlzZW5zZQojInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIgbXVzdCBiZSB1c2VkIHRvIHRocm93IG91dCBpbmNvbXBsZXRlIHZhbHVlcyAtIEkga25vdyBzb21lIGF1dGhvcnMgd2lsbCBjaGFuZ2UgZXZlcnkgemVybyB0byAxIHRvIGZpeCB0aGlzIApgYGB7cn0KZ3JvYjEgPC0gZ3JpZDo6Z3JvYlRyZWUoCiAgICBncmlkOjp0ZXh0R3JvYigKICAgICAgICBwYXN0ZSgKICAgICAgICAgICAgIlBlYXJzb24gQ29ycmVsYXRpb246ICIsCiAgICAgICAgICAgIHJvdW5kKGNvcigKICAgICAgICAgICAgICAgIENvbWJpbmRlZF9SRVMkbG9nMkZvbGRDaGFuZ2UsCiAgICAgICAgICAgICAgICBDb21iaW5kZWRfUkVTJEFTX2xvZzJGb2xkQ2hhbmdlLAogICAgICAgICAgICAgICAgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpLAogICAgICAgICAgICA0KQogICAgICAgICksCiAgICAgICAgeCA9IDAuNSwKICAgICAgICB5ID0gMC45NywKICAgICAgICBoanVzdCA9IDAsCiAgICAgICAgZ3AgPSBncGFyKGNvbCA9ICdibHVlJywgZm9udHNpemUgPSAxMSwgZm9udGZhY2UgPSAiYm9sZCIpCiAgICApCikKCmdncGxvdDI6OmdncGxvdChkYXRhID0gQ29tYmluZGVkX1JFUykgKyAKICAgIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gLjUpICsKICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gLjUpICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgICAgZGF0YSA9IENvbWJpbmRlZF9SRVMsCiAgICAgICAgbWFwcGluZyA9IGFlcyh5ID0gbG9nMkZvbGRDaGFuZ2UsIHggPSBBU19sb2cyRm9sZENoYW5nZSksCiAgICAgICAgYWxwaGEgPSA0LzEwLAogICAgICAgIHNpemUgPSAxLAogICAgICAgIGNvbG9yID0gJ2JsYWNrJwogICAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3Ntb290aCgKICAgICAgICBhZXMoeSA9IGxvZzJGb2xkQ2hhbmdlLCB4ID0gQVNfbG9nMkZvbGRDaGFuZ2UpLAogICAgICAgIG1ldGhvZCA9IGxtLAogICAgICAgIHNlID0gVFJVRSwKICAgICAgICBjb2xvciA9ICdmb3Jlc3RncmVlbicKICAgICkgKwogICAgZ2dwbG90Mjo6dGhlbWVfYncoKSArCiAgICBnZ3Bsb3QyOjphbm5vdGF0aW9uX2N1c3RvbShncm9iMSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9zbW9vdGgoCiAgICAgICAgZGF0YSA9IENvbWJpbmRlZF9SRVMsCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEFTX2xvZzJGb2xkQ2hhbmdlKSwKICAgICAgICBtZXRob2QgPSBsbSwKICAgICAgICBzZSA9IFRSVUUsCiAgICAgICAgY29sb3IgPSAnYmx1ZScKICAgICkKYGBgCgoKI2NoZWNrIGNvbG5hbWVzIG9mIFRQTV9OYXNfQVNfdXAKYGBge3J9CmNvbG5hbWVzKFRQTV9OYXNfQVNfdXApCmBgYAoKI3JlbmFtZSBBUyB0YWJsZSBuYW1lcyBzbyBJIGNhbiBjb21wYXJlIHRoZW0gd2l0aCBzZW5zZSB2YWx1ZXMgLSB0aGV5IHdpbGwgdGhlbiBoYXZlIGRpZmZlcmVudCBuYW1lcyBhbmQgbGFiZWxzIApgYGB7cn0KY29sbmFtZXMoVFBNX05hc19BU191cCkgPC0gYygKICAgICJnZW5lIiwgIkFTX2Jhc2VNZWFuIiwgIkFTX2xvZzJGb2xkQ2hhbmdlIiwgIkFTX2xmY1NFIiwgIkFTX3N0YXQiLAogICAgIkFTX3B2YWx1ZSIsICJBU19wYWRqIiwgIkF2Z19zaW5nbGVfVGFnX0FTX1RQTSIsICJBdmdfcGFyZW50YWxfQVNfVFBNIgopCmBgYAoKI2FkZCBzZW5zZSBleHByZXNzaW9uIGluZm8gb250byBoaWdoZXN0IEFTIHRhYmxlIHNvIHRob3NlIHBvaW50cyBjYW4gYmUgZ3JhcGhlZCBzZXBlcmF0ZWx5IApgYGB7cn0KSGlnaF91cF9BUyA8LSBtZXJnZShUUE1fTmFzX0FTX3VwLCByZXMxX24sIGJ5ID0gImdlbmUiKQpgYGAKCiNzY2F0dGVycGxvdCBub3cgd2l0aCBoaWdoIEFTIGhpZ2hsaWdodGVkIGluIHJlZCAKYGBge3J9Cmdyb2IyIDwtIGdyaWQ6Omdyb2JUcmVlKAogICAgZ3JpZDo6dGV4dEdyb2IoCiAgICAgICAgcGFzdGUoCiAgICAgICAgICAgICJQZWFyc29uIENvcnJlbGF0aW9uIE92ZXIgRXhwcmVzc2VkIEFTOiAiLAogICAgICAgICAgICByb3VuZCgKICAgICAgICAgICAgICAgIGNvcigKICAgICAgICAgICAgICAgICAgICBIaWdoX3VwX0FTJGxvZzJGb2xkQ2hhbmdlLAogICAgICAgICAgICAgICAgICAgIEhpZ2hfdXBfQVMkQVNfbG9nMkZvbGRDaGFuZ2UsCiAgICAgICAgICAgICAgICAgICAgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpLAogICAgICAgICAgICAgICAgNAogICAgICAgICAgICApCiAgICAgICAgKSwKICAgICAgICB4PSAwLjMsCiAgICAgICAgeSA9IDAuOTMsCiAgICAgICAgaGp1c3QgPSAwLAogICAgICAgIGdwID0gZ3Bhcihjb2wgPSAncmVkJywgZm9udHNpemUgPSAxMSwgZm9udGZhY2UgPSAiYm9sZCIpCiAgICApCikKCmdncGxvdDI6OmdncGxvdChkYXRhID0gQ29tYmluZGVkX1JFUykgKyAKICAgIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhID0gLjUpICsKICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gLjUpICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgICAgZGF0YSA9IENvbWJpbmRlZF9SRVMsCiAgICAgICAgbWFwcGluZyA9IGFlcyh5ID0gbG9nMkZvbGRDaGFuZ2UsIHggPSBBU19sb2cyRm9sZENoYW5nZSksCiAgICAgICAgYWxwaGEgPSA0LzEwLAogICAgICAgIHNpemUgPSAxLAogICAgICAgIGNvbG9yID0gJ2JsYWNrJwogICAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3Ntb290aCgKICAgICAgICBhZXMoeSA9IGxvZzJGb2xkQ2hhbmdlLCB4ID0gQVNfbG9nMkZvbGRDaGFuZ2UpLAogICAgICAgIG1ldGhvZCA9IGxtLAogICAgICAgIHNlID0gVFJVRSwKICAgICAgICBjb2xvciA9ICdmb3Jlc3RncmVlbicKICAgICkgKwogICAgZ2dwbG90Mjo6dGhlbWVfYncoKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogICAgICAgIGRhdGEgPSBIaWdoX3VwX0FTLCAKICAgICAgICBhZXMoeSA9IGxvZzJGb2xkQ2hhbmdlLHg9QVNfbG9nMkZvbGRDaGFuZ2UpLCAKICAgICAgICBjb2xvciA9ICJyZWQiLAogICAgICAgIHNpemUgPTEsIAogICAgICAgIGFscGhhID0gNC8xMAogICAgKSsKICAgIGdncGxvdDI6OmFubm90YXRpb25fY3VzdG9tKGdyb2IxKSArCiAgICBnZ3Bsb3QyOjphbm5vdGF0aW9uX2N1c3RvbShncm9iMikgKwogICAgZ2dwbG90Mjo6Z2VvbV9zbW9vdGgoCiAgICAgICAgZGF0YSA9IENvbWJpbmRlZF9SRVMsCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEFTX2xvZzJGb2xkQ2hhbmdlKSwKICAgICAgICBtZXRob2QgPSBsbSwKICAgICAgICBzZSA9IFRSVUUsCiAgICAgICAgY29sb3IgPSAnYmx1ZScKICAgICkgKwogICAgZ2dwbG90Mjo6Z2VvbV9zbW9vdGgoCiAgICAgICAgZGF0YSA9IEhpZ2hfdXBfQVMsCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEFTX2xvZzJGb2xkQ2hhbmdlKSwKICAgICAgICBtZXRob2QgPSBsbSwKICAgICAgICBzZSA9IFRSVUUsCiAgICAgICAgY29sb3IgPSAicmVkIgogICAgKQpgYGAKCgojIyBub3cgaXQgaXMgdGltZSB0byBkbyBncm91cGVkIGFuYWx5c2lzIDopIAojTWFrZSBhIG5ldyB2YXJpYWJsZSB0aGF0J3MgdGhlIHNhbWUgdGhpbmcgKG5lZWQgdGhpcyB0byByZW1vdmUgZ2VuZXMsIHNvIG5vIGdlbmUgaXMgYXNpZ25lZCB0byBtb3JlIHRoYW4gb25lIGdyb3VwKQpgYGB7cn0KRGVTZXEyX1NlbnNlX1Jlc3VsdHMgPC0gcmVzMV9uCmBgYAoKI25vdyB3ZSBhcmUgYmlubmluZyBnZW5lcyBieSBncm91cCBvZiBtUk5BIGV4cHJlc3Npb24KI2dyb3VwIDEgdXAgZ2VuZXMKI2dyb3VwIDUgZG93biBnZW5lcwpgYGB7cn0KZ3JwMV9EZVNlcTJfU2Vuc2VfUmVzdWx0cyA8LSBkcGx5cjo6ZmlsdGVyKHJlczFfbiwgbG9nMkZvbGRDaGFuZ2UgPiAyLCBwYWRqIDwgMC4wNSkKZ3JwNV9EZVNlcTJfU2Vuc2VfUmVzdWx0cyA8LSBkcGx5cjo6ZmlsdGVyKHJlczFfbiwgbG9nMkZvbGRDaGFuZ2UgPCAtMiwgcGFkaiA8IDAuMDUpCmBgYAoKI2dyb3VwIDMgIm5ldXRyYWwiCmBgYHtyfQpncnAzX0RlU2VxMl9TZW5zZV9SZXN1bHRzIDwtIGRwbHlyOjpmaWx0ZXIocmVzMV9uLCBsb2cyRm9sZENoYW5nZSA8IDEgLCBsb2cyRm9sZENoYW5nZSA+LTEgKQpgYGAKCiNyZW1vdmUgZ3JvdXAgMSBnZW5lcyBmcm9tIERlU2VxMl9TZW5zZV9SZXN1bHRzIApgYGB7cn0KRGVTZXEyX1NlbnNlX1Jlc3VsdHMgPC0gRGVTZXEyX1NlbnNlX1Jlc3VsdHNbCiAgICAhKERlU2VxMl9TZW5zZV9SZXN1bHRzJGdlbmUgJWluJSBncnAxX0RlU2VxMl9TZW5zZV9SZXN1bHRzJGdlbmUpLCAKXQpucm93KERlU2VxMl9TZW5zZV9SZXN1bHRzKSArIG5yb3coZ3JwMV9EZVNlcTJfU2Vuc2VfUmVzdWx0cykKYGBgCgojcmVtb3ZlIGdyb3VwIDUgZ2VuZXMgZnJvbSBEZVNlcTJfU2Vuc2VfUmVzdWx0cyAKYGBge3J9CkRlU2VxMl9TZW5zZV9SZXN1bHRzIDwtIERlU2VxMl9TZW5zZV9SZXN1bHRzWwogICAgIShEZVNlcTJfU2Vuc2VfUmVzdWx0cyRnZW5lICVpbiUgZ3JwNV9EZVNlcTJfU2Vuc2VfUmVzdWx0cyRnZW5lKSwgCl0KCm5yb3coRGVTZXEyX1NlbnNlX1Jlc3VsdHMpICsKbnJvdyhncnAxX0RlU2VxMl9TZW5zZV9SZXN1bHRzKSArCm5yb3coZ3JwNV9EZVNlcTJfU2Vuc2VfUmVzdWx0cykKCm5yb3coRGVTZXEyX1NlbnNlX1Jlc3VsdHMpCgpucm93KGdycDFfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpICsgbnJvdyhncnA1X0RlU2VxMl9TZW5zZV9SZXN1bHRzKQpgYGAKCiNyZW1vdmUgZ3JvdXAgMyBnZW5lcyBmcm9tIERlU2VxMl9TZW5zZV9SZXN1bHRzIApgYGB7cn0KRGVTZXEyX1NlbnNlX1Jlc3VsdHMgPC0gRGVTZXEyX1NlbnNlX1Jlc3VsdHNbCiAgICAhKERlU2VxMl9TZW5zZV9SZXN1bHRzJGdlbmUgJWluJSBncnAzX0RlU2VxMl9TZW5zZV9SZXN1bHRzJGdlbmUpLCAKXQpucm93KERlU2VxMl9TZW5zZV9SZXN1bHRzKQpucm93KGdycDNfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpCmBgYAoKI3Nhbml0eSBjaGVjayBjb3VudCByb3dzCmBgYHtyfQpucm93KGdycDFfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpIApucm93KGdycDVfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpCmBgYAoKI25vdyBmcm9tIG5vdCBncm91cCAxLDMsNSAtIHNwbGl0IGludG8gZ3JvdXAgMiBhbmQgNApgYGB7cn0KZ3JwMl9EZVNlcTJfU2Vuc2VfUmVzdWx0cyA8LSBmaWx0ZXIoRGVTZXEyX1NlbnNlX1Jlc3VsdHMsIGxvZzJGb2xkQ2hhbmdlID49MSkKZ3JwNF9EZVNlcTJfU2Vuc2VfUmVzdWx0cyA8LSBmaWx0ZXIoRGVTZXEyX1NlbnNlX1Jlc3VsdHMsIGxvZzJGb2xkQ2hhbmdlIDw9IC0xICkKYGBgCgojc2FuaXR5IGNoZWNrIGNvdW50IHJvd3MKYGBge3J9Cm5yb3coZ3JwMV9EZVNlcTJfU2Vuc2VfUmVzdWx0cykgKwpucm93KGdycDVfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpICsKbnJvdyhncnAzX0RlU2VxMl9TZW5zZV9SZXN1bHRzKSArCm5yb3coZ3JwMl9EZVNlcTJfU2Vuc2VfUmVzdWx0cykgKwpucm93KGdycDRfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpCmBgYAoKI3Nhbml0eSBjaGVjayBjb3VudCByb3dzCmBgYHtyfQpEZVNlcTJfU2Vuc2VfUmVzdWx0cyA8LSBEZVNlcTJfU2Vuc2VfUmVzdWx0c1sKICAgICEoRGVTZXEyX1NlbnNlX1Jlc3VsdHMkZ2VuZSAlaW4lIGdycDVfRGVTZXEyX1NlbnNlX1Jlc3VsdHMkZ2VuZSksIApdCgpucm93KERlU2VxMl9TZW5zZV9SZXN1bHRzKSArCm5yb3coZ3JwMV9EZVNlcTJfU2Vuc2VfUmVzdWx0cykgKwpucm93KGdycDVfRGVTZXEyX1NlbnNlX1Jlc3VsdHMpCgpucm93KERlU2VxMl9TZW5zZV9SZXN1bHRzKQoKbnJvdyhncnAxX0RlU2VxMl9TZW5zZV9SZXN1bHRzKSArIG5yb3coZ3JwNV9EZVNlcTJfU2Vuc2VfUmVzdWx0cykKYGBgCgojc2FuaXR5IGNoZWNrIGNvdW50IHJvd3MKI29ubHkgdGhpbmcgbGVmdCBpbiAiRGVTZXEyX1NlbnNlX1Jlc3VsdHMiIGlzIE5BIHJlc3VsdHMgCmBgYHtyfQpEZVNlcTJfU2Vuc2VfUmVzdWx0cyA8LSBEZVNlcTJfU2Vuc2VfUmVzdWx0c1sKICAgICEoRGVTZXEyX1NlbnNlX1Jlc3VsdHMkZ2VuZSAlaW4lIGdycDJfRGVTZXEyX1NlbnNlX1Jlc3VsdHMkZ2VuZSksIApdCkRlU2VxMl9TZW5zZV9SZXN1bHRzIDwtIERlU2VxMl9TZW5zZV9SZXN1bHRzWwogICAgIShEZVNlcTJfU2Vuc2VfUmVzdWx0cyRnZW5lICVpbiUgZ3JwNF9EZVNlcTJfU2Vuc2VfUmVzdWx0cyRnZW5lKSwgCl0KbnJvdyhEZVNlcTJfU2Vuc2VfUmVzdWx0cykKYGBgCgojbm93IHdlIGhhdmUgZ3JvdXBzIGJ5IHNlbnNlIGV4cHJlc3Npb24gY2hhbmdlCiNub3cgbWFrZSB0YWJsZSB0byBpbnRlZ3JhdGUgQVMgZXhwcmVzc2lvbiBpbmZvIApgYGB7cn0KZ3JvdXAxIDwtIG1lcmdlKGdycDFfRGVTZXEyX1NlbnNlX1Jlc3VsdHMsIHJlczFfbl9hcywgYnkgPSAiZ2VuZSIpCmdyb3VwMiA8LSBtZXJnZShncnAyX0RlU2VxMl9TZW5zZV9SZXN1bHRzLCByZXMxX25fYXMsIGJ5ID0gImdlbmUiKQpncm91cDMgPC0gbWVyZ2UoZ3JwM19EZVNlcTJfU2Vuc2VfUmVzdWx0cywgcmVzMV9uX2FzLCBieSA9ICJnZW5lIikKZ3JvdXA0IDwtIG1lcmdlKGdycDRfRGVTZXEyX1NlbnNlX1Jlc3VsdHMsIHJlczFfbl9hcywgYnkgPSAiZ2VuZSIpCmdyb3VwNSA8LSBtZXJnZShncnA1X0RlU2VxMl9TZW5zZV9SZXN1bHRzLCByZXMxX25fYXMsIGJ5ID0gImdlbmUiKQpgYGAKCiN3aGF0IGhhcHBlbnMgbmV4dCBpcyBob3cgaSBtYWtlIHZpb2xpbiBwbG90cy4gCiNJIGZpZ3VyZWQgdGhpcyBvdXQgbGlrZSBhIHllYXIgYWdvIGFuZCBoYXZlIGNvcHkgcGFzdGVkIHRoaXMgY29kZSBhIGJ1bmNoLgojdGhpcyBpcyB0aGUgYmlucyAKYGBge3J9Cm1STkExIDwtIGRhdGEuZnJhbWUoQVNfbG9nMkZvbGRDaGFuZ2UgPSBncm91cDEkQVNfbG9nMkZvbGRDaGFuZ2UpCm1STkEyIDwtIGRhdGEuZnJhbWUoQVNfbG9nMkZvbGRDaGFuZ2UgPSBncm91cDIkQVNfbG9nMkZvbGRDaGFuZ2UpCm1STkEzIDwtIGRhdGEuZnJhbWUoQVNfbG9nMkZvbGRDaGFuZ2UgPSBncm91cDMkQVNfbG9nMkZvbGRDaGFuZ2UpCm1STkE0IDwtIGRhdGEuZnJhbWUoQVNfbG9nMkZvbGRDaGFuZ2UgPSBncm91cDQkQVNfbG9nMkZvbGRDaGFuZ2UpCm1STkE1IDwtIGRhdGEuZnJhbWUoQVNfbG9nMkZvbGRDaGFuZ2UgPSBncm91cDUkQVNfbG9nMkZvbGRDaGFuZ2UpCmBgYAoKI25vdyB0aGUgbGl0dGxlIHNlcGVyYXRlIGJpbnMgYXJlIGdsdWVkIHRvZ2V0aGVyIApgYGB7cn0KIyBOb3csIGNvbWJpbmUgeW91ciB0d28gZGF0YWZyYW1lcyBpbnRvIG9uZS4gIAojIEZpcnN0IG1ha2UgYSBuZXcgY29sdW1uIGluIGVhY2ggdGhhdCB3aWxsIGJlIAojIGEgdmFyaWFibGUgdG8gaWRlbnRpZnkgd2hlcmUgdGhleSBjYW1lIGZyb20gbGF0ZXIuCm1STkExJGV4cHJlc3Npb24gPC0gJ092ZXJfRXhwcmVzc2VkJwptUk5BMiRleHByZXNzaW9uIDwtICdPdmVyX0V4cHJlc3NlZF9ub3Rfc2lnJwptUk5BMyRleHByZXNzaW9uIDwtICdOZXV0cmFsJwptUk5BNCRleHByZXNzaW9uIDwtICdVbmRlcl9FeHByZXNzZWRfbm90X3NpZycKbVJOQTUkZXhwcmVzc2lvbiA8LSAnVW5kZXJfRXhwcmVzc2VkJwoKIyBhbmQgY29tYmluZSBpbnRvIHlvdXIgbmV3IGRhdGEgZnJhbWUgdmVnTGVuZ3RocwpkYXRhZnJhbWUxIDwtIHJiaW5kKG1STkEyLCBtUk5BMywgbVJOQTQsIG1STkE1LCBtUk5BMSkKYGBgCgojbm93IHdlIHdlIG1ha2UgYSB2aW9saW4gcGxvdCAKYGBge3J9CnAgPC0gZ2dwbG90Mjo6Z2dwbG90KAogICAgZGF0YWZyYW1lMSwKICAgIGFlcyhmYWN0b3IoZXhwcmVzc2lvbiksIGZpbGwgPSBleHByZXNzaW9uLCBBU19sb2cyRm9sZENoYW5nZSkKKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwoCiAgICAgICAgdmFsdWVzID0gYygiIzlGOUJBMiIsICJsaW1lZ3JlZW4iLCAiIzQ0QTA0MyIsICIjRDFCM0VDIiwgIiM4MjVDQTYiKQogICAgKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkKcApgYGAKCiNub3cgd2Ugd2UgbWFrZSBhIHZpb2xpbiBwbG90IHdpdGggcCB2YWx1ZXMgCmBgYHtyfQpteV9jb21wYXJpc29ucyA8LSBsaXN0KAogICAgYygnTmV1dHJhbCcsICdPdmVyX0V4cHJlc3NlZCcpLAogICAgYygnTmV1dHJhbCcsICdVbmRlcl9FeHByZXNzZWQnKSwKICAgIGMoJ1VuZGVyX0V4cHJlc3NlZCcsICdPdmVyX0V4cHJlc3NlZCcpCikKCnAgPC0gZ2dwbG90Mjo6Z2dwbG90KAogICAgZGF0YWZyYW1lMSwKICAgIGFlcyhmYWN0b3IoZXhwcmVzc2lvbiksIGZpbGwgPSBleHByZXNzaW9uLCBBU19sb2cyRm9sZENoYW5nZSkKKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwoCiAgICAgICAgdmFsdWVzID0gYygiIzlGOUJBMiIsICJsaW1lZ3JlZW4iLCAiIzQ0QTA0MyIsICIjRDFCM0VDIiwgIiM4MjVDQTYiKQogICAgKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkgKwogICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucykKcApgYGAKCiNub3cgd2VyZSBnb2luZyB0byBkbyB0aGUgc2FtZSB0aGluZwojdGhlIGJpbnMgc3RheSB0aGUgc2FtZQojYnV0IGluIHRoZSBiaW5zIHdlcmUgYXJlIHB1dHRpbmcgQVMgZXhwcmVzc2lvbiBsZXZlbCAKYGBge3J9CmNvbG5hbWVzKEFTX1RQTSlbY29sbmFtZXMoQVNfVFBNKSA9PSAibmFtZSJdIDwtICJnZW5lIgoKVFBNX2dyb3VwMSA8LSBtZXJnZShncnAxX0RlU2VxMl9TZW5zZV9SZXN1bHRzLCBBU19UUE0sIGJ5ID0gImdlbmUiKQpUUE1fZ3JvdXAyIDwtIG1lcmdlKGdycDJfRGVTZXEyX1NlbnNlX1Jlc3VsdHMsIEFTX1RQTSwgYnkgPSAiZ2VuZSIpClRQTV9ncm91cDMgPC0gbWVyZ2UoZ3JwM19EZVNlcTJfU2Vuc2VfUmVzdWx0cywgQVNfVFBNLCBieSA9ICJnZW5lIikKVFBNX2dyb3VwNCA8LSBtZXJnZShncnA0X0RlU2VxMl9TZW5zZV9SZXN1bHRzLCBBU19UUE0sIGJ5ID0gImdlbmUiKQpUUE1fZ3JvdXA1IDwtIG1lcmdlKGdycDVfRGVTZXEyX1NlbnNlX1Jlc3VsdHMsIEFTX1RQTSwgYnkgPSAiZ2VuZSIpCmBgYAoKYGBge3J9CmNvbG5hbWVzKFRQTV9ncm91cDEpCmBgYAoKI21ha2luZyBkYXRhIGZyYW1lcyB0byBwdXQgaW50byB2aW9saW4gcGxvdApgYGB7cn0KVFBNX21STkExIDwtIGRhdGEuZnJhbWUoQVNfTGV2ZWxfRGVwbGV0aW9uID0gVFBNX2dyb3VwMSRBdmdfc2luZ2xlX1RhZ19BU19UUE0pClRQTV9tUk5BMiA8LSBkYXRhLmZyYW1lKEFTX0xldmVsX0RlcGxldGlvbiA9IFRQTV9ncm91cDIkQXZnX3NpbmdsZV9UYWdfQVNfVFBNKQpUUE1fbVJOQTMgPC0gZGF0YS5mcmFtZShBU19MZXZlbF9EZXBsZXRpb24gPSBUUE1fZ3JvdXAzJEF2Z19zaW5nbGVfVGFnX0FTX1RQTSkKVFBNX21STkE0IDwtIGRhdGEuZnJhbWUoQVNfTGV2ZWxfRGVwbGV0aW9uID0gVFBNX2dyb3VwNCRBdmdfc2luZ2xlX1RhZ19BU19UUE0pClRQTV9tUk5BNSA8LSBkYXRhLmZyYW1lKEFTX0xldmVsX0RlcGxldGlvbiA9IFRQTV9ncm91cDUkQXZnX3NpbmdsZV9UYWdfQVNfVFBNKQpgYGAKCiNnbHVlaW5nIHRoZSBkYXRhIGZyYW1lcyBpbnRvIG9uZSAKYGBge3J9CiMgTm93LCBjb21iaW5lIHlvdXIgdHdvIGRhdGFmcmFtZXMgaW50byBvbmUuICAKIyBGaXJzdCBtYWtlIGEgbmV3IGNvbHVtbiBpbiBlYWNoIHRoYXQgd2lsbCBiZSAKIyBhIHZhcmlhYmxlIHRvIGlkZW50aWZ5IHdoZXJlIHRoZXkgY2FtZSBmcm9tIGxhdGVyLgpUUE1fbVJOQTEkZXhwcmVzc2lvbiA8LSAnT3Zlcl9FeHByZXNzZWQnClRQTV9tUk5BMiRleHByZXNzaW9uIDwtICdPdmVyX0V4cHJlc3NlZF9ub3Rfc2lnJwpUUE1fbVJOQTMkZXhwcmVzc2lvbiA8LSAnTmV1dHJhbCcKVFBNX21STkE0JGV4cHJlc3Npb24gPC0gJ1VuZGVyX0V4cHJlc3NlZF9ub3Rfc2lnJwpUUE1fbVJOQTUkZXhwcmVzc2lvbiA8LSAnVW5kZXJfRXhwcmVzc2VkJwoKIyBhbmQgY29tYmluZSBpbnRvIHlvdXIgbmV3IGRhdGEgZnJhbWUgdmVnTGVuZ3RocwpkYXRhZnJhbWUyIDwtIHJiaW5kKFRQTV9tUk5BMiwgVFBNX21STkEzLCBUUE1fbVJOQTQsIFRQTV9tUk5BNSwgVFBNX21STkExKQpgYGAKCiNtYWtlIHZpb2xpbiBwbG90CmBgYHtyfQpteV9jb21wYXJpc29ucyA8LSBsaXN0KAogICAgYygnTmV1dHJhbCcsICdPdmVyX0V4cHJlc3NlZCcpLAogICAgYygnTmV1dHJhbCcsICdVbmRlcl9FeHByZXNzZWQnKSwKICAgIGMoJ1VuZGVyX0V4cHJlc3NlZCcsICdPdmVyX0V4cHJlc3NlZCcpCikKCnAyIDwtIGdncGxvdDI6OmdncGxvdCgKICAgIGRhdGFmcmFtZTIsCiAgICBhZXMoZmFjdG9yKGV4cHJlc3Npb24pLCBmaWxsID0gZXhwcmVzc2lvbiwgQVNfTGV2ZWxfRGVwbGV0aW9uKQopICsgZ2dwbG90Mjo6Z2VvbV92aW9saW4oZHJhd19xdWFudGlsZXMgPSBjKDAuMjUsIDAuNSwgMC43NSkpICsKICAgIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKAogICAgICAgIHZhbHVlcyA9IGMoIiM5RjlCQTIiLCAibGltZWdyZWVuIiwgIiM0NEEwNDMiLCAiI0QxQjNFQyIsICIjODI1Q0E2IikKICAgICkgKwogICAgZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpICsKICAgIGdncGxvdDI6OnlsaW0oMCwgMTAwKQpwMgpgYGAKCgojbWFrZSB2aW9saW4gcGxvdCBidXQgbm93IHdpdGggcCB2YWx1ZXMgCmBgYHtyfQpteV9jb21wYXJpc29ucyA8LSBsaXN0KAogICAgYygnTmV1dHJhbCcsICdPdmVyX0V4cHJlc3NlZCcpLAogICAgYygnTmV1dHJhbCcsICdVbmRlcl9FeHByZXNzZWQnKSwKICAgIGMoJ1VuZGVyX0V4cHJlc3NlZCcsICdPdmVyX0V4cHJlc3NlZCcpCikKCnAyIDwtIGdncGxvdDI6OmdncGxvdCgKICAgIGRhdGFmcmFtZTIsCiAgICBhZXMoZmFjdG9yKGV4cHJlc3Npb24pLCBmaWxsID0gZXhwcmVzc2lvbiwgQVNfTGV2ZWxfRGVwbGV0aW9uKQopICsKICAgIGdncGxvdDI6Omdlb21fdmlvbGluKGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LCAwLjUsIDAuNzUpKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCgKICAgICAgICB2YWx1ZXMgPSBjKCIjOUY5QkEyIiwgImxpbWVncmVlbiIsICIjNDRBMDQzIiwgIiNEMUIzRUMiLCAiIzgyNUNBNiIpCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArCiAgICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zLCBtZXRob2QgPSAidC50ZXN0IikKcDIKYGBgCgoKI25vdyBJIGFtIGdhdGluZyBieSBmb2xkIGNoYW5nZSA+MiBpbnN0ZWFkIG9mIDQgCmBgYHtyfQpPTkVfQVNfcmVzMU5hYjNfdXAgPC0gZHBseXI6OmZpbHRlcigKICAgIHJlczFfbl9hcywKICAgIEFTX2xvZzJGb2xkQ2hhbmdlID4gMSwKICAgIEFTX3BhZGogPCAwLjA1CikKT05FX0FTX3JlczFOYWIzX2Rvd24gPC0gZHBseXI6OmZpbHRlcigKICAgIHJlczFfbl9hcywKICAgIEFTX2xvZzJGb2xkQ2hhbmdlIDwgLTEsCiAgICBBU19wYWRqIDwgMC4wNQopCmBgYAoKI2NvbXBhcmluZyBiZXR3ZWVuIGZvbGQgY2hhbmdlID4yIGluc3RlYWQgb2YgNCAKYGBge3J9Ck9ORV9UUE1fTmFzX0FTX3VwIDwtIGRwbHlyOjppbm5lcl9qb2luKAogICAgT05FX0FTX3JlczFOYWIzX3VwLCBDdXR0b2ZmX1RQTV9BUywgYnkgPSAiZ2VuZSIKKQpucm93KFRQTV9OYXNfQVNfdXApCm5yb3coT05FX1RQTV9OYXNfQVNfdXApCmBgYAoKI05ldyBTZW5zZSBmaWx0ZXJzIApgYGB7cn0KT05FX3JlczFOYWIzX3VwIDwtIGRwbHlyOjpmaWx0ZXIocmVzMV9uLCBsb2cyRm9sZENoYW5nZSA+IDEsIHBhZGogPCAwLjA1KQpPTkVfcmVzMU5hYjNfZG93biA8LSBkcGx5cjo6ZmlsdGVyKHJlczFfbiwgbG9nMkZvbGRDaGFuZ2UgPCAtMSwgcGFkaiA8IDAuMDUpCmBgYAoKCiNuZXcgZnVuY3Rpb25hbCBSTkEgY2F0YWdvcnkgCmBgYHtyfQpPTkVfVXBBU19Eb3duTVJOQSA8LSBpbm5lcl9qb2luKE9ORV9UUE1fTmFzX0FTX3VwLCBPTkVfcmVzMU5hYjNfZG93biwgYnkgPSAiZ2VuZSIpCm5yb3coT05FX1VwQVNfRG93bk1STkEpCmBgYAoKI3dyaXRlIG5hbWVzIG9ubHkgdG8gZmlsZQojdGhhbmtzIGZvciB3cml0aW5nIHRoaXMgS3JpcwpgYGB7cn0KZmlsZUNvbm4gPC0gcGFzdGUocF90eHQsICJmdW5jdGlvbmFsX0FTX3Rlc3RfbGlzdC50eHQiLCBzZXAgPSAiLyIpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKE9ORV9VcEFTX0Rvd25NUk5BJGdlbmUpLCBmaWxlQ29ubikKY2xvc2UoZmlsZUNvbm4pCmBgYAoKI2NhbGMgb3ZlcmxhcHMgCmBgYHtyfQpPTkVfVXBBU19VcE1STkEgPC0gZHBseXI6OmlubmVyX2pvaW4oCiAgICBPTkVfVFBNX05hc19BU191cCwgT05FX3JlczFOYWIzX3VwLCBieSA9ICJnZW5lIgopCm5yb3coT05FX1VwQVNfVXBNUk5BKQpucm93KE9ORV9UUE1fTmFzX0FTX3VwKQpucm93KE9ORV9yZXMxTmFiM191cCkKYGBgCgoKYCNIRVJFYAojI25vdyBJIGFtIGdvaW5nIHRvIGNvbXBhcmUgdG8gNTc4MSBhbmQgMiBXVCBRIGFuZCBHMQojc28gSSBnb3R0YSByZWFkIHRoYXQgZGF0YSBpbiAKYGBge3J9CldUX0FTX2RpZmZfZXhwcmVzc2lvbiA8LSByZWFkLmRlbGltKAogICAgcGFzdGUocF9mdWxsLCAicmVzX29yZGVyX0FTX0RpZmZfZXhwcmVzc2lvbi50eHQiLCBzZXAgPSAiLyIpLAogICAgaGVhZGVyID0gVFJVRQopCldUX1RQTSA8LSByZWFkLmRlbGltKAogICAgcGFzdGUocF9mdWxsLCAiV1RfUV9HMV9UUE0udHh0Iiwgc2VwID0gIi8iKSwKICAgIGhlYWRlciA9IFRSVUUKKQpgYGAKCiNmaWx0ZXJlZCBieSBleHByZXNzaW9uIApgYGB7cn0KV1RfQVNfVVBfUSA8LSBkcGx5cjo6ZmlsdGVyKAogICAgV1RfQVNfZGlmZl9leHByZXNzaW9uLAogICAgbG9nMkZvbGRDaGFuZ2UgPiAxLAogICAgcGFkaiA8IDAuMDUKKQpgYGAKCiNjYWxjIHdoYXQgaGlnaCBBUyBpcyAKYGBge3J9CnF1YW50aWxlKFdUX1RQTSRBdmdfUV9JUF9BTlRJU2Vuc2UsIHByb2JzID0gYygwLjUsIDAuNzUsIDAuOCwwLjg1LCAwLjksIDAuOTUpKSAKYGBgCiNvbmNlIGFnYWluIEkgYW0gZ2F0aW5nIGF0IDgwJSAKYGBge3J9CldUX2hpZ2hfbGV2ZWxfQVMgPC0gZHBseXI6OmZpbHRlcihXVF9UUE0sIEF2Z19RX0lQX0FOVElTZW5zZSA+IDE0KQpgYGAKCiNjaGVjayBjb2xuYW1lcyAKYGBge3J9CmNvbG5hbWVzKFdUX2hpZ2hfbGV2ZWxfQVMpCmBgYAoKCiNtZXJnZSBoaWdoIGxldmVsIGFuZCBvdmVyZXhwcmVzc2VkIApgYGB7cn0KY29sbmFtZXMoV1RfQVNfVVBfUSlbY29sbmFtZXMoV1RfQVNfVVBfUSkgPT0gIm5hbWUiXSA8LSAiZ2VuZSIKV1RfYmVzdF9BUyA8LSBtZXJnZShXVF9BU19VUF9RLCBXVF9oaWdoX2xldmVsX0FTLCBieS54ID0gImdlbmUiLCBieS55ID0gImVuc2dlbmUiKQpgYGAKCiNub3cgY29tcGFyZSBXVCB0byBOYWIzIGV4cGVyaW1lbnQgCmBgYHtyfQpBU190ZXN0ZWQgPC0gbWVyZ2UoV1RfYmVzdF9BUywgSGlnaF91cF9BUywgYnkgPSAiZ2VuZSIpCm5yb3coQVNfdGVzdGVkKQpucm93KFdUX2Jlc3RfQVMpCm5yb3coSGlnaF91cF9BUykKYGBgCgojb2YgdGhlIDE4MCBhYm92ZSAtIGhvdyBtYW55IGFyZSBmdW5jdGlvbmFsPwpgYGB7cn0KRnVuY3Rpb25hbF9XVCA8LSBtZXJnZShPTkVfVXBBU19Eb3duTVJOQSwgQVNfdGVzdGVkLCBieSA9ICJnZW5lIikKbnJvdyhGdW5jdGlvbmFsX1dUKQpucm93KE9ORV9VcEFTX0Rvd25NUk5BKQpucm93KEFTX3Rlc3RlZCkKCmBgYAoKI21ha2luZyBhIGxpc3Qgb2YgZ2VuZSBuYW1lcyBmcm9tIE5hYjMgZGF0YSBzbyBJIGNhbiBoaWdobGlnaHQgdGhvc2UgZ2VuZXMgaW4gV1QgZGF0YSAKYGBge3J9Ck9ORV9VcEFTX0Rvd25NUk5BX2xpc3QgPC0gT05FX1VwQVNfRG93bk1STkEgJT4lIGRwbHlyOjpzZWxlY3QoYygiZ2VuZSIpKQpPTkVfVFBNX05hc19BU191cF9saXN0IDwtIE9ORV9UUE1fTmFzX0FTX3VwICU+JSBkcGx5cjo6c2VsZWN0KGMoImdlbmUiKSkKCm5yb3coT05FX1VwQVNfRG93bk1STkFfbGlzdCkKbnJvdyhPTkVfVFBNX05hc19BU191cF9saXN0KQpgYGAKI2FsbCBnZW5lcyBpbiBXVCAtIEFTIHRwbSBhbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gCmBgYHtyfQpjb2xuYW1lcyhXVF9BU19kaWZmX2V4cHJlc3Npb24pWwogICAgY29sbmFtZXMoV1RfQVNfZGlmZl9leHByZXNzaW9uKSA9PSAibmFtZSIKXSA8LSAiZ2VuZSIKV1RfZGF0YSA8LSBtZXJnZShXVF9UUE0sIFdUX0FTX2RpZmZfZXhwcmVzc2lvbiwgYnkueCA9ICJlbnNnZW5lIiwgYnkueSA9ICJnZW5lIikKYGBgCgojZ3JhcGggaXQgYW5kIGl0IGlzIGEgYmxvYiAKYGBge3J9Cmdyb2I3IDwtIGdyaWQ6Omdyb2JUcmVlKAogICAgZ3JpZDo6dGV4dEdyb2IoCiAgICAgICAgcGFzdGUoCiAgICAgICAgICAgICJQZWFyc29uIENvcnJlbGF0aW9uIDogIiwKICAgICAgICAgICAgcm91bmQoCiAgICAgICAgICAgICAgICBjb3IoCiAgICAgICAgICAgICAgICAgICAgV1RfZGF0YSRBdmdfUV9JUF9BTlRJU2Vuc2UsCiAgICAgICAgICAgICAgICAgICAgV1RfZGF0YSRsb2cyRm9sZENoYW5nZSwKICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIgogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIDQKICAgICAgICAgICAgKQogICAgICAgICksCiAgICAgICAgeCA9IDAuNSwKICAgICAgICB5ID0gMC45NywKICAgICAgICBoanVzdCA9IDAsCiAgICAgICAgZ3AgPSBncGFyKGNvbCA9ICJibGFjayIsIGZvbnRzaXplID0gMTEsIGZvbnRmYWNlID0gImJvbGQiKQogICAgKQopCgoKZ2dwbG90Mjo6Z2dwbG90KGRhdGEgPSBXVF9kYXRhKSArIAogICAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICAgICAgICBtYXBwaW5nID0gYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeD0gQXZnX1FfSVBfQU5USVNlbnNlKSwKICAgICAgICBhbHBoYSA9IDIvMTAsCiAgICAgICAgc2l6ZSA9IDEKICAgICkgKwogICAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKAogICAgICAgIHRyYW5zID0gbG9nMl90cmFucygpLAogICAgICAgIGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMiIsIGZ1bmN0aW9uKHgpIDJeeCksCiAgICAgICAgbGFiZWxzID0gdHJhbnNfZm9ybWF0KCJsb2cyIiwgbWF0aF9mb3JtYXQoMl4ueCkpCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX2J3KCkrCiAgICBnZ3Bsb3QyOjphbm5vdGF0aW9uX2N1c3RvbShncm9iNykrCiAgICBnZ3Bsb3QyOjpnZW9tX3Ntb290aCgKICAgICAgICBkYXRhID0gV1RfZGF0YSwKICAgICAgICBhZXMoeSA9IGxvZzJGb2xkQ2hhbmdlLCB4ID0gQXZnX1FfSVBfQU5USVNlbnNlKSwKICAgICAgICBtZXRob2QgPSBsbSwKICAgICAgICBzZSA9IFRSVUUsCiAgICAgICAgY29sb3IgPSAnYmxhY2snCiAgICApCmBgYAoKCgojbWFwIE5hYjMgZ2VuZXMgdG8gV1QgZGF0YSAKYGBge3J9CldUX2RhdGFfTmFiM19TZW5zaXRpdmVfZ2VuZXMgPC0gbWVyZ2UoCiAgICBXVF9kYXRhLCBPTkVfVFBNX05hc19BU191cF9saXN0LCBieS54ID0gImVuc2dlbmUiLCBieS55ID0gImdlbmUiCikKCldUX2RhdGFfZnVuY3Rpb25hbF9BUyA8LSBtZXJnZSgKICAgIFdUX2RhdGEsIE9ORV9VcEFTX0Rvd25NUk5BX2xpc3QsIGJ5LnggPSAiZW5zZ2VuZSIsIGJ5LnkgPSAiZ2VuZSIKKQpgYGAKCiNncmFwaCBpdCBhbmQgaXQgaXMgMiBibG9icyEhIDopIApgYGB7cn0KZ3JvYjggPC0gZ3JpZDo6Z3JvYlRyZWUoCiAgICBncmlkOjp0ZXh0R3JvYigKICAgICAgICBwYXN0ZSgKICAgICAgICAgICAgIlBlYXJzb24gQ29ycmVsYXRpb24gOiAiLAogICAgICAgICAgICByb3VuZCgKICAgICAgICAgICAgICAgIGNvcigKICAgICAgICAgICAgICAgICAgICBXVF9kYXRhX05hYjNfU2Vuc2l0aXZlX2dlbmVzJEF2Z19RX0lQX0FOVElTZW5zZSwKICAgICAgICAgICAgICAgICAgICBXVF9kYXRhX05hYjNfU2Vuc2l0aXZlX2dlbmVzJGxvZzJGb2xkQ2hhbmdlLAogICAgICAgICAgICAgICAgICAgIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgNAogICAgICAgICAgICApCiAgICAgICAgKSwKICAgICAgICB4ID0gMC41LAogICAgICAgIHkgPSAwLjkzLAogICAgICAgIGhqdXN0ID0gMCwKICAgICAgICBncCA9IGdwYXIoY29sID0gJyNEMzc1MzgnLCBmb250c2l6ZSA9IDExLCBmb250ZmFjZSA9ICJib2xkIikKICAgICkKKQoKZ2dwbG90Mjo6Z2dwbG90KGRhdGEgPSBXVF9kYXRhKSArIAogICAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICAgICAgICBtYXBwaW5nID0gYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeD0gQXZnX1FfSVBfQU5USVNlbnNlKSwKICAgICAgICBhbHBoYSA9IDIvMTAsCiAgICAgICAgc2l6ZSA9IDEKICAgICkgKwogICAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKAogICAgICAgIHRyYW5zID0gbG9nMl90cmFucygpLAogICAgICAgIGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMiIsIGZ1bmN0aW9uKHgpIDJeeCksCiAgICAgICAgbGFiZWxzID0gdHJhbnNfZm9ybWF0KCJsb2cyIiwgbWF0aF9mb3JtYXQoMl4ueCkpKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9idygpICsKICAgIGdncGxvdDI6OmFubm90YXRpb25fY3VzdG9tKGdyb2I3KSsKICAgIGdncGxvdDI6OmFubm90YXRpb25fY3VzdG9tKGdyb2I4KSsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoZGF0YSA9IFdUX2RhdGFfTmFiM19TZW5zaXRpdmVfZ2VuZXMsIAogICAgICAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEF2Z19RX0lQX0FOVElTZW5zZSksIAogICAgICAgICAgICAgY29sb3IgPSAnI0QzNzUzOCcsCiAgICAgICAgICAgICBzaXplID0gMSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9zbW9vdGgoCiAgICAgICAgZGF0YSA9IFdUX2RhdGEsCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEF2Z19RX0lQX0FOVElTZW5zZSksCiAgICAgICAgbWV0aG9kID0gbG0sCiAgICAgICAgc2UgPSBUUlVFLAogICAgICAgIGNvbG9yID0gJ2JsYWNrJwogICAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3Ntb290aCgKICAgICAgICBkYXRhID0gV1RfZGF0YV9OYWIzX1NlbnNpdGl2ZV9nZW5lcywKICAgICAgICBhZXMoeSA9IGxvZzJGb2xkQ2hhbmdlLCB4ID0gQXZnX1FfSVBfQU5USVNlbnNlKSwKICAgICAgICBtZXRob2QgPSBsbSwKICAgICAgICBzZSA9IFRSVUUsCiAgICAgICAgY29sb3IgPScjRDM3NTM4JwogICAgKQpgYGAKCiNncmFwaCBpdCBhZ2FpbiAKYGBge3J9Cmdyb2I5IDwtIGdyaWQ6Omdyb2JUcmVlKAogICAgZ3JpZDo6dGV4dEdyb2IoCiAgICAgICAgcGFzdGUoCiAgICAgICAgICAgICJQZWFyc29uIENvcnJlbGF0aW9uIDoiLAogICAgICAgICAgICByb3VuZCgKICAgICAgICAgICAgICAgIGNvcigKICAgICAgICAgICAgICAgICAgICBXVF9kYXRhX2Z1bmN0aW9uYWxfQVMkQXZnX1FfSVBfQU5USVNlbnNlLAogICAgICAgICAgICAgICAgICAgIFdUX2RhdGFfZnVuY3Rpb25hbF9BUyRsb2cyRm9sZENoYW5nZSwKICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIgogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIDQKICAgICAgICAgICAgKQogICAgICAgICksCiAgICAgICAgeCA9IDAuNSwKICAgICAgICB5ID0gMC45MywKICAgICAgICBoanVzdCA9IDAsCiAgICAgICAgZ3AgPSBncmlkOjpncGFyKGNvbCA9ICdyZWQnLCBmb250c2l6ZSA9IDExLCBmb250ZmFjZSA9ICJib2xkIikKICAgICkKKQoKCmdncGxvdDI6OmdncGxvdChkYXRhID0gV1RfZGF0YSkgKyAKICAgIGdncGxvdDI6Omdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh5PSBsb2cyRm9sZENoYW5nZSwgeD0gQXZnX1FfSVBfQU5USVNlbnNlKSwgYWxwaGEgPSAyLzEwLCBzaXplID0gMSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKAogICAgICAgIHRyYW5zID0gbG9nMl90cmFucygpLAogICAgICAgIGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMiIsIGZ1bmN0aW9uKHgpIDJeeCksCiAgICAgICAgbGFiZWxzID0gdHJhbnNfZm9ybWF0KCJsb2cyIiwgbWF0aF9mb3JtYXQoMl4ueCkpCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX2J3KCkrCiAgICBnZ3Bsb3QyOjphbm5vdGF0aW9uX2N1c3RvbShncm9iNykrCiAgICBnZ3Bsb3QyOjphbm5vdGF0aW9uX2N1c3RvbShncm9iOSkrCiAgICBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogICAgICAgIGRhdGEgPSBXVF9kYXRhX2Z1bmN0aW9uYWxfQVMsIAogICAgICAgIGFlcyh5ID0gbG9nMkZvbGRDaGFuZ2UsIHggPSBBdmdfUV9JUF9BTlRJU2Vuc2UpLCAKICAgICAgICBjb2xvciA9J3JlZCcsCiAgICAgICAgc2l6ZSA9IDEKICAgICkgKwogICAgZ2dwbG90Mjo6Z2VvbV9zbW9vdGgoCiAgICAgICAgZGF0YSA9IFdUX2RhdGEsCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEF2Z19RX0lQX0FOVElTZW5zZSksCiAgICAgICAgbWV0aG9kID0gbG0sCiAgICAgICAgc2UgPSBUUlVFLAogICAgICAgIGNvbG9yPSdibGFjaycKICAgICkgKwogICAgZ2dwbG90Mjo6Z2VvbV9zbW9vdGgoCiAgICAgICAgZGF0YSA9IFdUX2RhdGFfZnVuY3Rpb25hbF9BUywKICAgICAgICBhZXMoeSA9IGxvZzJGb2xkQ2hhbmdlLCB4ID0gQXZnX1FfSVBfQU5USVNlbnNlKSwKICAgICAgICBtZXRob2QgPSBsbSwKICAgICAgICBzZSA9IFRSVUUsCiAgICAgICAgY29sb3IgPSAncmVkJwogICAgKQpgYGAKCiNhbGwgb24gb25lLiBidXN5LCB2ZXJ5IGhhcmQgdG8gbG9vayBhdC4gCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YSA9IFdUX2RhdGEpICsgCiAgICBnZ3Bsb3QyOjpnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeT0gbG9nMkZvbGRDaGFuZ2UsIHg9IEF2Z19RX0lQX0FOVElTZW5zZSksIGFscGhhID0gMi8xMCwgc2l6ZSA9IDEpICsKICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cygKICAgICAgICB0cmFucyA9IGxvZzJfdHJhbnMoKSwKICAgICAgICBicmVha3MgPSB0cmFuc19icmVha3MoImxvZzIiLCBmdW5jdGlvbih4KSAyXngpLAogICAgICAgIGxhYmVscyA9IHRyYW5zX2Zvcm1hdCgibG9nMiIsIG1hdGhfZm9ybWF0KDJeLngpKQogICAgKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9idygpKwogICAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICAgICAgICBkYXRhID0gV1RfZGF0YV9OYWIzX1NlbnNpdGl2ZV9nZW5lcywgCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEF2Z19RX0lQX0FOVElTZW5zZSksIAogICAgICAgIGNvbG9yID0gJyNEMzc1MzgnLAogICAgICAgIHNpemUgPSAxCiAgICApICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgICAgZGF0YSA9IFdUX2RhdGFfZnVuY3Rpb25hbF9BUywgCiAgICAgICAgYWVzKHkgPSBsb2cyRm9sZENoYW5nZSwgeCA9IEF2Z19RX0lQX0FOVElTZW5zZSksIAogICAgICAgIGNvbG9yID0gJ3JlZCcsCiAgICAgICAgc2l6ZSA9IDEKICAgICkKYGBgCg==